临界区是不是确保由一个线程修改的任何数据类型的共享变量对其他线程可见? [复制]

Posted

技术标签:

【中文标题】临界区是不是确保由一个线程修改的任何数据类型的共享变量对其他线程可见? [复制]【英文标题】:Does a critical section makes sure that shared variables of any data type modified by one thread becomes visible to the other threads? [duplicate]临界区是否确保由一个线程修改的任何数据类型的共享变量对其他线程可见? [复制] 【发布时间】:2017-03-15 12:48:28 【问题描述】:

我想在多个线程之间共享一些变量,共享变量可以是任何数据类型(原始数据类型、数组、结构或类的实例等)。

如果我将访问这些共享变量的代码包含在临界区中,一个线程所做的更改是否会对其他线程可见?

我知道对于原始数据类型,临界区方法有效,但我不确定其他数据类型,即使我相信答案是肯定的(因为 CPU 不关心数据类型,它是只是处理位)。

【问题讨论】:

借助像 Windows 这样的现代多任务保护系统,单个进程中的所有线程都可以访问进程中的所有数据。所有非局部变量都已“共享”。它们对进程中的所有线程都是“可见的”。也许如果您详细说明您遇到的实际问题,我们可能会为您提供更好的帮助? 我认为问题在于缓存问题。多个线程共享的变量应声明为volatile,以确保所有线程立即看到更新。 我想你已经问过这个问题了。也许不止一次。 @Someprogrammerdude,当您在多 CPU 主机上运行多个线程时,“可见性”是一个大问题。当然,所有线程都看到所有相同的变量,但它们不一定就这些变量的更新发生的时间(或顺序)达成一致。编程系统的“内存模型”告诉您何时可以依赖一个线程所做的更新对其他线程可见:en.wikipedia.org/wiki/Memory_model_(programming) 内存就是内存。不管是简单的整数还是复杂的结构。这只是记忆。 【参考方案1】:

由于 CriticalSection 的目的是对不同线程/内核的访问进行序列化,因此您可以期望这些函数尽其所能确保跨线程的正确共享访问。这将包括内存屏障之类的东西。

【讨论】:

更具体地说:当一个线程锁定一个互斥体时,它应该能够看到其他线程在另一个线程解锁之前所做的所有更新相同的互斥体。【参考方案2】:

是的,进入/退出关键有效同步 CPU 缓存 - 全局变量 - 因为在这个函数中总是执行带有 lock 前缀的指令 - 这是关键点。

例如阅读KeMemoryBarrier(这等于MemoryBarrier 宏)

此外,xchg 指令隐式包含 lock 前缀,强制处理器硬件完成内存 xchg 指令之前的所有指令的操作 在它启动内存操作之前的指令 xchg 指令。

作为结果,EnterCriticalSection / LeaveCriticalSection 和任何互锁函数(使用 lock 前缀)在此处有效。请注意KeMemoryBarrier 在随机内存上执行lock xchg真的是lock xchg [esp],eax,但这已经足够了

另请阅读Memory Barriers/Fences

原子指令和软件锁 原子指令,例如 x86 上的“lock ...”指令,实际上是一个完整的障碍 因为他们锁定内存子系统以执行操作并拥有 保证总订单,即使跨 CPU。软件锁通常 使用内存屏障或原子指令来实现可见性 并保持程序顺序。

【讨论】:

以上是关于临界区是不是确保由一个线程修改的任何数据类型的共享变量对其他线程可见? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

进程同步

9内核同步介绍

用互斥锁保护临界区

Unix网络编程-同步

竞态条件和临界区

互斥锁- pthread_mutex