C++ 写一次,同时读多次。。。无锁

C++ 写一次,同时读多次。。。无锁,c++,c,multithreading,thread-safety,C++,C,Multithreading,Thread Safety,这是一个关于一个作者和多个同时读者的问题 我希望这会激怒一些人,我可能会因为敢于问这个问题而被否决,但我想了解它是如何工作的。我知道互斥体和原子是什么,没必要教我 假设我有一个可供多个线程访问的内存位置(一个全局变量或我共享的指针)。它的大小与体系结构相同,假设它是64位系统上8字节大小的单个无符号整数。它被设置为0 让我们假设有一千个线程在循环中读取它。如果它的0他们做了一些重要的事情,如果它的1他们做了另一件重要的事情,如果它既不是0也不是1他们发射了一枚核导弹 然后一个线程(正好一个,不是

这是一个关于一个作者和多个同时读者的问题

我希望这会激怒一些人,我可能会因为敢于问这个问题而被否决,但我想了解它是如何工作的。我知道互斥体和原子是什么,没必要教我

假设我有一个可供多个线程访问的内存位置(一个全局变量或我共享的指针)。它的大小与体系结构相同,假设它是64位系统上8字节大小的单个无符号整数。它被设置为
0

让我们假设有一千个线程在循环中读取它。如果它的
0
他们做了一些重要的事情,如果它的
1
他们做了另一件重要的事情,如果它既不是
0
也不是
1
他们发射了一枚核导弹

然后一个线程(正好一个,不是多个)用值
1
覆盖这个内存位置。会发生什么

看。。。我的理论是没有什么不好的事情发生,这是好的。没有数据损坏。在
0
1
之间没有半路。一个周期显示为
0
,下一个周期显示为
1
。不需要互斥或原子。我说得对吗?如果没有,原因是什么

编辑:系统要求我解释为什么这与另一个问题不同。答案是因为它和那个问题不一样。如果你不确定它有什么不同,请再读一遍,尤其是以问号结尾的部分

然后一个线程(正好一个,不是多个)用值1覆盖这个内存位置。会发生什么

看。。。我的理论是没有什么不好的事情发生,这是好的

你错了

如果一个线程写入内存位置,而您没有任何同步机制,也没有使用原子,那么您无法保证其他线程会看到更改

变量=1下运行着一整套技术几乎每一层都可以接受这个更新

在程序集级别和CPU级别,没有任何东西强迫从级别1缓存写回主内存

如果你只有一个变量和一个变化,那还不错。有些线程会看到更新的值,有些则不会。传播更新可能需要任意长的时间。你仍然可以称之为最终的一致性

但是一旦有了两个变量,写入值和读取值之间就会出现不一致


将“内存模型一致性C++”放入您最喜欢的搜索引擎中以了解更多详细信息。

线程通常不直接从内存读/写,而是直接从内存读/写到缓存。 缓存是一个更小但更快的内存

要使某个读卡器线程读取1而不是0,首先需要发生两件事:

  • 写入线程必须已将其缓存写回内存
  • 读卡器线程必须已从内存重新加载其缓存
  • 这些事件发生的时间取决于体系结构、操作系统、其他进程和代码

    每个读卡器线程在读取1之前都将读取0。 从0到1的切换可能根本不会发生,并且可能在不同线程的不同时间发生


    这就是原子的存在,它们可以在不同线程的高速缓存中执行同步。< /P> C或C++?这两种语言的方法完全不同。“技术上,它不是C或C++问题,而是一个架构问题。”阿拉斯代尔:如果这是一个架构问题,什么架构?C++中,程序的行为是未定义的。句号。请注意,“未定义的行为”意味着语言定义不会告诉您程序的功能。因此,您可以随心所欲地猜测,也可以分析底层硬件,或许可以整理出您认为会发生什么。但是,当行为未定义时,编译器不需要生成合理的代码,也不需要每次编译时都生成相同的代码,尤其是在更改编译器设置或编译器版本时。很简单,不能保证行为是一致的。当然,在大多数情况下,任何合理的编译器/内核/内存控制器都会正确地处理它,尽管数据可能不会像答案中所说的那样传输到其他线程,但它不会是0或1以外的内容。但是,没有保证,因为标准中没有定义,并且假设您使用的是非常特定的材料/系统,而这些材料/系统并不费心实施,您不知道会发生什么。你的情况永远不可能发生,因为任何一段代码,只要足够接近安全的东西(比如原子弹),就允许完全没有未定义的行为。这个问题需要关注。它是询问一些计算机类架构的具体行为,真实的或想象的,当前的或未来的。与C和C++有关的一些不明确的方式,这只是他一半的问题。更重要的部分是,“它可以通过0和1以外的任何其他值”缓存协议(如MESI)专门传播这些值,假设您在缓存一致性机器上。如果您使用的是线程,那么您就在一台缓存一致的机器上。所以,这个值(最终)会传播,并且只会是零或一。所以你是说答案是“没有什么不好的事情发生”?没有腐败或崩溃之类的吗?公平地说,这种情况必须一直错误地发生。而使用原子意味着所有线程都将收到更改通知?也就是说,原子变量意味着一个变量没有保存在缓存中?@Alasdair这同样取决于您的编译器和目标体系结构:如果您的代码可以在单个CPU上运行,那么编译器可能会决定将其保存在L3缓存中,您在该CPU上运行的所有线程都可以读取它。任何一个