不同步的c++多线程
C++ multithreading without synchronization
c++:我有2个线程,每一个增量'n'通过做n++ (n是全局变量)假设我不使用任何线程同步,我的要求是打印0,1,2,....10.
int n = 0 //global variable
线程1:n++;
printf("%d", n);
线程2:n++;
printf("%d", n);
在没有线程同步的情况下执行程序会有问题吗,或者它会满足我的要求(1,2,3…10)
c++标准说这个程序有未定义的行为,任何事情都可能发生。任何,包括重复打印相同的数字,不打印任何内容,使程序崩溃或擦除硬盘。
1.10 (intro.multithread)
如果其中一个修改了内存位置(1.7),而另一个读取或修改了相同的内存位置,则两个表达式求值会发生冲突。
…如果程序的执行包含两个潜在的并发冲突操作,其中至少一个不是原子操作,并且两个操作都发生在另一个操作之前,则程序的执行包含数据竞争,下面描述的信号处理程序的特殊情况除外。任何这样的数据竞争都会导致未定义的行为。
对于被多个线程并发修改的变量,应该使用std::atomic<int>
,或者与互斥锁同步,以避免由于数据竞争而导致的未定义行为。
对于您的用例,您需要确保每次变量更新时打印它的值,即增量和打印必须自动发生。简单地自动更新整数是不够的,您必须确保打印增量的结果,而不是在稍后的某个时间(当其他线程可能已经更改了它,如Rotem的回答所示)打印变量的值。
可以这样做:
std::atomic<int> n{0}; // global variable
线程1:printf("%d", ++n);
线程2:printf("%d", ++n);
现在,每次线程增加变量的增量结果将直接传递给printf
。
这假设对stdout
的写入是线程安全的,并且是按顺序发生的,为了避免这种假设,使用互斥锁来创建一个临界区,更新变量并打印它,防止其他线程在互斥锁被锁定时增加变量或打印:
int n = 0 //global variable
std::mutex mtx; // global mutex
线程1:{
std::lock_guard<std::mutex> lock(mtx);
++n;
printf("%d", n);
}
线程2:{
std::lock_guard<std::mutex> lock(mtx);
++n;
printf("%d", n);
}
注意:仍然不能保证两个线程交替递增和打印,完全有可能第一个线程执行10次递增并打印整个输出,而第二个线程没有机会运行。
执行程序会有问题吗?
这是可能发生的(而且,正如墨菲所说:)。
理性递增是不是原子的,通常使用以下三个基本操作来实现:
- 从内存中读取值
- 给 值加1
- 将值写回内存
注:printf()
也不是原子。
线程之间的上下文切换可能随时发生,在n++
、printf()
或这两个操作之间。竞争条件可能发生在上下文切换期间,如果n
的访问未同步
考虑以下场景:
- 线程1读取值(值为10)线程2读取值(值为10)
- 线程1给值 加1
- 线程1将值写入内存(值为11)
- 线程2给值 加1
- 线程2将值写入内存(值仍然是11)
您期望的值是12,但实际是11。
结论 n
为共享资源。
对共享资源的并发(读写)访问必须同步!
- 在C++中使用cURL和多线程
- 多线程双缓冲区
- 为什么我的多线程作业队列崩溃
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 为什么一个向量上的多线程操作很慢
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 全局变量 多读取器 一个写入器多线程安全?
- boost::文件系统::recursive_directory_iterator多线程安全
- 如何阻止TensorFlow的多线程
- 如何在多线程中正确使用unique_ptr进行多态性?
- 并发/多线程:是否可以以这种方式生成相同的输出?
- sigwait() 在多线程程序中不起作用
- 多线程程序中出现意外的内存泄漏
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 多线程比没有线程C++慢
- 具有 C++11 多线程的特征库
- 通过安装信号处理程序关闭多线程应用程序
- 成员变量在多线程 C++ 时自行更改
- 尝试从头开始实现Leetcode的FizzBuzz多线程问题。收到"libc++abi.dylib: terminating"错误