多线程环境下,程序真是危机四伏

简介: 本文依旧是#线程安全#、#锁# 这两个老生常谈的概念的延续, 我的知识体系也是在不断迭代更新,不断精炼。

你管这也叫线程安全?


      最近大意了,竟然想将《面试官:实现一个带值变更通知能力的Dictionary》一文中的临界锁只应用到写操作。


d950f7b8b45f46862eb430cd300af282.png


内心旁白:读操作又不会修改数据,无论是新值还是旧值,反正能读到。


不过我又快速清醒了,临界锁还真就得这么加。临界锁的目的是保证这一段代码逻辑不会被打断。


假如只应用写锁:

07152574f9a82dd2c5ec6196936c25de.png


某线程执行到写锁前(刚触发了一次变通通知),这时cpu时间片轮转或抢占, 切换到另外的线程又把这段代码执行了一次(因为字典key-value还没被前线程覆写),这样一次value变更实际执行了两次变更操作,这就悲剧了。


结合之前《你管这叫线程安全?》一文中多线程对于i++i--带来的线程不安全的理解。


你品你细品:


本次线程安全是在宏观代码行执行层面, 上次的i++ 是在微观寄存器层面归根到底让多线程在多核环境下:代码逻辑不能被打断(代码执行节奏可能被打断)


多线程环境下,程序运行真是危机四伏。


微软官方怎么说?


还没完, 我还从微软官方原子操作[1]找到一段话:


Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.


直译起来:


① bool char byte sbyte uint int float 和引用类型上的读写是原子操作;

② 由以上类型定义的枚举类型操作也是原子类型;

③ long ulong double decimal和用户定义类型上的读写不保证是原子操作;

④ 除了库文件本身设计了线程安全,一般况下下都不保证读写是原子操作, 这也包括i++i--


这段文字是不是刷新了某些童靴的认知(包括在下):


1. 以后使用long num=8888;时要留个心眼,你也许会读到long类型的部分字节。


2.直译第①点说引用类型的读写是原子操作,第③点说用户类型不保证原子操作,但是大部分的用户类型是引用类型,这不互相矛盾了吗?


我向微软官方提出了我的这个疑问,有兴趣可以关注这个 github issue[2]


说说我的看法:


直译第①点中说int,引用类型等读写操作是原子操作:应该想表达的是纯粹的赋值操作, 比如


int a =1;                               //  赋值:线程安全Student s = new Student {};             // 引用赋值:线程安全Student  s2= s;                         // 引用赋值:线程安全


针对引用类型Dictionary的其他操作自然不是线程安全的。


依据这个思路, 第①③点就不矛盾了。


That's All, 本文依旧是#线程安全#、#锁# 这两个老生常谈的概念的延续, 我的知识体系也是在不断迭代更新,不断精炼。

相关文章
|
2月前
|
Java 开发者
如何通过易语言多线程提升程序响应速度
如何通过易语言多线程提升程序响应速度
204 62
|
1月前
|
安全 Java
线程安全的艺术:确保并发程序的正确性
在多线程环境中,确保线程安全是编程中的一个核心挑战。线程安全问题可能导致数据不一致、程序崩溃甚至安全漏洞。本文将分享如何确保线程安全,探讨不同的技术策略和最佳实践。
41 6
|
2月前
|
Java 开发者
如何通过易语言多线程提升程序响应速度?
如何通过易语言多线程提升程序响应速度?
|
2月前
|
监控 Java API
|
4月前
|
Rust 并行计算 安全
揭秘Rust并发奇技!线程与消息传递背后的秘密,让程序性能飙升的终极奥义!
【8月更文挑战第31天】Rust 以其安全性和高性能著称,其并发模型在现代软件开发中至关重要。通过 `std::thread` 模块,Rust 支持高效的线程管理和数据共享,同时确保内存和线程安全。本文探讨 Rust 的线程与消息传递机制,并通过示例代码展示其应用。例如,使用 `Mutex` 实现线程同步,通过通道(channel)实现线程间安全通信。Rust 的并发模型结合了线程和消息传递的优势,确保了高效且安全的并行执行,适用于高性能和高并发场景。
79 0
|
4月前
|
开发框架 Android开发 iOS开发
跨平台开发的双重奏:Xamarin在不同规模项目中的实战表现与成功故事解析
【8月更文挑战第31天】在移动应用开发领域,选择合适的开发框架至关重要。Xamarin作为一款基于.NET的跨平台解决方案,凭借其独特的代码共享和快速迭代能力,赢得了广泛青睐。本文通过两个案例对比展示Xamarin的优势:一是初创公司利用Xamarin.Forms快速开发出适用于Android和iOS的应用;二是大型企业借助Xamarin实现高性能的原生应用体验及稳定的后端支持。无论是资源有限的小型企业还是需求复杂的大公司,Xamarin均能提供高效灵活的解决方案,彰显其在跨平台开发领域的强大实力。
55 0
|
4月前
|
Java 调度
|
4月前
|
缓存 Java 容器
多线程环境中的虚假共享是什么?
【8月更文挑战第21天】
42 0