我正在使用多线程程序中的共享链表。我没有使用锁存器(互斥锁),而是依靠CAS操作来确保插入和删除的正确性。所有插入和删除都发生在链表(LIFO)的头部。该程序没有按预期工作,它随机导致分段错误并退出。有什么想法吗? 这是我的程序的简化版本。它在大约1%的时间内打破了四个线程。
struct Node {
unsigned long num;
Node* next;
};
Node* head = NULL;
#define NUM_THREADS 4L
#define Rounds 10000L
#define Iterations 100L
#define SumPerRound ((Iterations-1)*Iterations/2)
#define SumPerThread (SumPerRound * Rounds)
#define ExpectedSum (SumPerThread * NUM_THREADS)
unsigned long totalSum = 0;
void* Worker(void*) {
for (unsigned int r = 0; r < Rounds; r++) {
for (unsigned int i = 0; i < Iterations; i++) {
Node* n = new Node();
n-> num = i;
do {
n->next = head;
} while (!__sync_bool_compare_and_swap(&head, n->next, n));
}
for (unsigned int i = 0; i < Iterations; i++) {
Node* n;
do {
n = head;
assert(n);
} while (!__sync_bool_compare_and_swap(&head, n, n->next));
__sync_fetch_and_add(&totalSum, n->num);
delete n;
}
}
return NULL;
}
答案 0 :(得分:0)
我发现了问题。当两个并发线程尝试删除头部的同一节点时。他们都抓住链表的头部(n =头部)。其中一个被暂停,而另一个设法从链表中删除该节点,处理并删除它。当另一个线程尝试删除该节点时,它会执行CAS操作。 CAS操作的第三个参数(n-> next)尝试取消引用另一个线程删除的指针。我有一个解决这个问题的方法,但它太复杂了,不能在这里讨论。