C 仅递增/递减变量时是否需要互斥?
我有一个带整数字段的结构,比如C 仅递增/递减变量时是否需要互斥?,c,synchronization,pthreads,mutex,C,Synchronization,Pthreads,Mutex,我有一个带整数字段的结构,比如 struct s { int a; int b; int c; int max; }; struct s mystruct = {0, 0, 0, 0}; // Global var 然后我有N个线程,它们有时必须在前三个字段上执行++或--之类的操作,有时必须读取它们,然后更新max字段。我必须在这里使用互斥吗?如果是,则仅在读取/更新max时需要,还是始终需要?为什么?如果我只是增加或减少前三个字段,那么一个线程是否在另一个线
struct s {
int a;
int b;
int c;
int max;
};
struct s mystruct = {0, 0, 0, 0}; // Global var
然后我有N个线程,它们有时必须在前三个字段上执行
++
或--
之类的操作,有时必须读取它们,然后更新max
字段。我必须在这里使用互斥吗?如果是,则仅在读取/更新max
时需要,还是始终需要?为什么?如果我只是增加或减少前三个字段,那么一个线程是否在另一个线程之前运行有关系吗?并发的通用规则是:如果以非原子方式并发访问内存位置,并且不是所有访问都是读取的,那么必须对访问进行排序。可以通过锁定互斥锁来序列化访问,也可以通过一些较低级别的操作(如有序原子访问或有序围栏)来实施排序
如果所有访问都是读取的,则唯一允许进行无序访问的时间。例如,多个线程可以读取(非原子)常量而无需排序。如果正在执行的操作不是原子操作,则需要同步对变量的访问。 考虑单个变量<代码> A/COD>的初始值,例如,5。 现在我们有两个线程T1和T2,都想增加它。增量操作是如何分解的,如果它不是原子的(只是一个例子,可能是其他方式) 1) 将
值读入临时位置。
2) 递增并将临时位置写回a
现在考虑一个场景T1先执行这个操作,然后在完成第1步之后先由T2抢占:
T1:1)将a
读入temp1
=>temp1=5
T2:1)将a
读入temp2
=>temp2=5
T2:2)将temp2+1
写入a
=>a=6
T1:2)将temp1+1
写入a
=>a=6
因此a
的最终值将是6
而不是7
,这就像问你是否只需要锁上房子的前门一样,后门仅用于偶尔来访者,并不重要。请参阅,例如,您可以使用stdatomic.h
有用的练习:定义“排序”的技术概念是“发生在之前”和“与同步”。访问不必排序。如果访问是原子性的,并且内存的顺序是松弛的,那么它们就没有顺序。