当只有 inc/decrementing 个变量时是否需要互斥锁?
Is a mutex necessary when only inc/decrementing a variable?
我有一个带有一些整数字段的结构,比如
struct s {
int a;
int b;
int c;
int max;
};
struct s mystruct = {0, 0, 0, 0}; // Global var
然后我有 N 个线程,有时必须在前三个字段上做 ++
或 --
之类的事情,有时必须读取它们然后更新 max
场地。我必须在这里使用互斥锁吗?如果是,是仅在 reading/updating max
时还是始终需要?为什么?如果我只是递增或递减前三个字段,一个线程在另一个线程之前运行是否重要?
并发的通用规则是:如果以非原子方式并发访问内存位置,并且并非所有访问都是读取,则必须对访问进行排序。可以通过锁定互斥锁来序列化访问,或者通过一些较低级别的操作(如有序原子访问或有序栅栏)来强制执行排序。
如果所有 的访问都是读取,那么您唯一一次被允许无序 访问。例如。多个线程可以读取一个(非原子)常量而无需排序。
如果您执行的操作不是原子操作,则需要同步对变量的访问。
考虑一个初始值为 5 的单个变量 a
的场景。
现在我们有两个线程 T1 和 T2,都想增加它。如何分解增量操作,以防它不是原子的(只是一个例子,可能是其他方式)?
1) 将 a
值读入临时位置。
2) 递增并将临时位置写回 a
。
现在考虑这样一个场景,T1先执行这个操作,然后T2在完成第1步后抢占:
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
。
我有一个带有一些整数字段的结构,比如
struct s {
int a;
int b;
int c;
int max;
};
struct s mystruct = {0, 0, 0, 0}; // Global var
然后我有 N 个线程,有时必须在前三个字段上做 ++
或 --
之类的事情,有时必须读取它们然后更新 max
场地。我必须在这里使用互斥锁吗?如果是,是仅在 reading/updating max
时还是始终需要?为什么?如果我只是递增或递减前三个字段,一个线程在另一个线程之前运行是否重要?
并发的通用规则是:如果以非原子方式并发访问内存位置,并且并非所有访问都是读取,则必须对访问进行排序。可以通过锁定互斥锁来序列化访问,或者通过一些较低级别的操作(如有序原子访问或有序栅栏)来强制执行排序。
如果所有 的访问都是读取,那么您唯一一次被允许无序 访问。例如。多个线程可以读取一个(非原子)常量而无需排序。
如果您执行的操作不是原子操作,则需要同步对变量的访问。
考虑一个初始值为 5 的单个变量 a
的场景。
现在我们有两个线程 T1 和 T2,都想增加它。如何分解增量操作,以防它不是原子的(只是一个例子,可能是其他方式)?
1) 将 a
值读入临时位置。
2) 递增并将临时位置写回 a
。
现在考虑这样一个场景,T1先执行这个操作,然后T2在完成第1步后抢占:
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
。