是否可能发生不应该发生的情况?
这要部分取决于变量的类型。如果变量是字符串(字符的长数组),那么如果写入程序和读取程序同时访问它,读取程序所看到的内容是完全未定义的。
这就是为什么 pthreads 提供了互斥锁和其他协调机制的原因。
这是否意味着只有该线程才能读写它,而其他线程则不能?
互斥锁确保最多只有一个正在使用互斥锁的线程可以获得继续执行的权限,所有其他使用相同互斥锁的线程将被阻塞,直到第一个线程释放互斥锁。因此,如果代码编写正确,任何时候只有一个线程将能够访问该变量。如果代码编写不正确,则可能出现以下情况:
以上行为都是不希望出现的,但仅有互斥锁的存在并不能防止出现这些行为。
尽管如此,只要小心使用互斥锁,您的代码就可以合理地使用互斥锁,并且全局变量的访问将得到适当的控制。在通过互斥锁获得权限后,任何线程都可以修改变量或仅读取变量。无论哪种情况都不会受到其他线程的干扰。
首先,对于C/C++中未同步读/写的变量并不会产生任何异常或系统错误,但它可能会生成应用程序级别的错误——主要是因为你很难完全理解内存如何被访问以及是否是原子性的,除非你查看生成汇编代码。当你在没有同步的情况下访问共享内存时,多核CPU可能会导致难以调试的竞争条件。
因此,第二点:在处理共享内存时,您应该始终使用同步,例如互斥锁。互斥锁很便宜,如果使用得当,它不会影响性能。经验法则是尽可能短地保持锁定状态,只需在读取/增加/写入共享内存期间保持锁定状态。
然而,根据您的描述,似乎其中一个线程除了等待共享内存改变状态之外什么也没有做——这是一种坏的多线程设计,会造成不必要的CPU负担,因此
第三点:如果您正在尝试从一个线程向另一个线程发送“消息”,请考虑使用信号量(sem_create/wait/post)进行线程间同步。
正如其他人所说,当通过“普通”对象在线程之间进行通信时,您必须注意竞争条件。除了相对较重的互斥锁和其他锁结构外,新的C标准(C11)提供了原子类型和操作,保证不会出现竞争。大多数现代处理器都为此类类型提供指令,并且许多现代编译器(特别是Linux上的gcc)已经为这些操作提供了适当的接口。
int
在读写时是"原子性"的,但这并不是保证。你很可能可以不使用互斥锁来保护此值,但你可能会遇到奇怪的问题,并且时间问题非常难以复现和诊断。我可能不会冒险,但这取决于你的系统/应用程序有多重要。如果阅读器每次都要休眠12秒钟,那么如果编写者疯狂地改变它关于时间的想法,这并不重要。所以,是的,你有权利采取(经过计算的)风险。但是,如果事情出了问题,请不要哭泣。 - Jonathan Leffler