【发布时间】:2016-12-04 23:53:57
【问题描述】:
我在 2 个线程之间有一个共享结构变量:
struct {
long a;
long b;
long c;
} myStruct;
struct myStruct A;
A 的所有 3 个字段都初始化为零。然后第一个线程将更新它们:
A.a = 1;
A.b = 2;
A.c = 3;
第二个线程将从它读取。我要确保的是第二个线程将作为一个整体读取 A,无论是旧值 {0,0,0},还是新值 {1,2,3},而不是像 {1,2,0 这样的损坏}。 该结构不适合 64 位,所以我不能使用 gcc 的内置原子,我也不想使用互斥锁,所以我想出了 2 个保护标志:
struct {
long a;
long b;
long c;
volatile int beginCount, endCount;
} A;
那么第一个线程将:
A.beginCount++;
A.a = 1;
A.b = 2;
A.c = 3;
A.endCount++;
并且 2nd 将循环直到它得到一个一致的结构:
int begin, end;
myStruct tmp;
do {
begin = A.beginCount;
end = A.endCount;
tmp = A;
} while (!(begin == A.beginCount && end == A.endCount && A.beginCount == A.endCount))
// now tmp will be either {0,0,0} or {1,2,3}
那两个守卫标志够吗?如果不是,请指出可能破坏它的线程调度的特定组合。
编辑1:我不想使用互斥锁的原因是第一个线程具有高优先级,它不应该等待任何东西。如果第 2 个线程在读取时第 1 个线程要写入,那么第 1 个线程仍然会写入,并且第 2 个线程必须重做读取,直到它获得一致的值。我们不能用互斥锁做到这一点,至少我不知道。
编辑 2:关于环境:这段代码在多处理器系统上运行,我为每个线程专用了 1 个完整的 cpu 核心。
编辑 3:我知道没有互斥锁或原子的同步非常棘手。我已经列出了我能想到的所有组合,但找不到任何破解密码的组合。所以,请不要只说它不起作用,如果你指出它什么时候会坏,我将非常感激。
【问题讨论】:
-
不,他们不是。两个线程可以同时读取
beginCount,然后添加一个,并保存结果。现在您的临界区中有两个线程,但beginCount是 1。您需要使用原子或互斥体来解决这个问题。 -
只有第一个线程修改共享结构,第二个线程只读取它
标签: c multithreading gcc consistency