Linux上C语言中的POSIX线程和全局变量

Linux上C语言中的POSIX线程和全局变量,c,linux,multithreading,C,Linux,Multithreading,如果我有两个线程和一个全局变量(一个线程不断循环读取变量,另一个线程不断循环写入变量),会发生不应该发生的事情吗?(例如:例外、错误)。如果是这样的话,有什么办法可以防止这种情况。我读过关于互斥锁的书,它们允许一个线程独占访问一个变量。这是否意味着只有该线程可以读写它而没有其他线程?这是否意味着只有该线程可以读写它而没有其他线程? 这意味着一次只能有一个线程读取或写入全局变量。 这两个线程之间不会访问全局变量,也不会在任何给定时间点同时访问它 简而言之,全局变量的访问权限是 会发生不应该发生的事

如果我有两个线程和一个全局变量(一个线程不断循环读取变量,另一个线程不断循环写入变量),会发生不应该发生的事情吗?(例如:例外、错误)。如果是这样的话,有什么办法可以防止这种情况。我读过关于互斥锁的书,它们允许一个线程独占访问一个变量。这是否意味着只有该线程可以读写它而没有其他线程?

这是否意味着只有该线程可以读写它而没有其他线程?

这意味着一次只能有一个线程读取或写入全局变量。
这两个线程之间不会访问全局变量,也不会在任何给定时间点同时访问它

简而言之,全局变量的访问权限是

会发生不应该发生的事情吗

这部分取决于变量的类型。如果变量是一个字符串(长字符数组),那么如果编写器和读取器同时访问它,那么读取器将看到的内容是完全未定义的

这就是为什么互斥锁和其他协调机制是由pthreads提供的

这是否意味着只有该线程可以读写它,而没有其他线程

互斥锁确保最多有一个使用互斥锁的线程有权继续。使用同一互斥锁的所有其他线程都将被挂起,直到第一个线程释放互斥锁为止。因此,如果代码编写正确,在任何时候,只有一个线程能够访问变量。如果代码编写不正确,则:

  • 一个线程可能会访问变量,而不检查它是否具有访问权限
  • 一个线程可能会获取互斥锁,并且永远不会释放它
  • 一个线程可能会在不通知另一个线程的情况下销毁互斥体
这些都不是令人满意的行为,但仅仅存在互斥并不能阻止这些行为的发生


然而,您的代码可以合理地小心地使用互斥,然后对全局变量的访问将得到适当的控制。虽然它通过互斥体拥有权限,但任一线程都可以修改变量,或者只是读取变量。任何一个线程都不会受到另一个线程的干扰。

如果线程实际上只是一个生产者和一个消费者,那么(排除编译器错误),然后

1) 将变量标记为易失性,以及

2) 确保它正确对齐,以避免交叉存取和存储


将允许您在不锁定的情况下执行此操作。

首先;在C/C++中,变量的非同步读/写不会生成任何异常或系统错误,但它会生成应用程序级错误——主要是因为除非查看生成的汇编程序,否则不可能完全理解内存是如何访问的,以及它是否是原子的。当您在不同步的情况下访问共享内存时,多核CPU可能会产生难以调试的竞争条件

因此

第二;在处理共享内存时,应该始终使用同步(如互斥锁)。互斥锁很便宜;因此,如果操作正确,它不会真正影响性能。经验法则;保持lcok尽可能短,例如仅在读取/递增/写入共享内存期间

然而,根据您的描述,听起来您的一个线程什么也不做,只是在做某件事之前等待共享内存更改状态——这是一个糟糕的多线程设计,需要花费不必要的CPU消耗,所以


第三;如果您正试图像其他人所说的那样从一个线程向另一个线程发送“消息”,请查看使用信号量(sem_create/wait/post)在线程之间进行同步,在通过“普通”对象在线程之间进行通信时,您必须注意争用条件。除了互斥锁和其他相对较重的锁结构外,新的C标准(C11)还提供了保证无竞争的原子类型和操作。大多数现代处理器为此类类型和许多现代编译器(特别是linux上的编译器)提供指令已经为这些操作提供了适当的接口。

让它们读写而不锁定安全吗?还是应该让每个线程锁定变量并进行读写,然后在完成时解锁?我不确定是否同意这个答案--只有一个进程可以使用互斥锁,但是另一个进程中的编程错误很容易允许它在没有先锁定的情况下读取/写入变量。@bobmoch:通常,不锁定的情况下读取和写入是不安全的。在某些非常特殊的情况下,它是安全的,但您最好不要担心它,因为无争用的锁非常快。@Soren:没有一种编程语言可以“安全”地避免编程错误。@bobmoch:您必须在读或写操作时锁定全局变量,否则会有争用条件。这只适用于(1)一些架构具有(2)某些数据类型和(3)如果不需要阻塞语义和(4)如果全局变量不引用共享状态。除非在非常特殊的情况下,否则这是不可能推荐的。(顺便说一句,无论数据是否对齐,CPU和编译器都会对获取和存储进行重新排序。使用
volatile
只能防止编译器进行某些特定更改,CPU仍然可以对其进行重新排序。)全局数据是睡眠计时器的整数。一个线程从它从其他地方获得的其他数据中确定睡眠,而另一个线程执行一个函数,然后在第一个线程设置为变量的时间内睡眠。sleep全局变量不需要是“current”,如线程1将其设置为12,然后线程2将其读取为1