【发布时间】:2020-02-19 04:05:44
【问题描述】:
让我们考虑以下使用链表实现的单读/单写队列。
struct queue {
queue() {
tail = head = &reserved;
n = 0;
}
void push(item *it) {
tail->next = it;
tail = it;
n++;
}
item* pop() {
while (n == used);
++used;
head = head->next;
return head;
}
item reserved;
item *tail, *head;
int used = 0;
std::atomic <int> n;
}
现在我发现使用volatile int n 可以使我的编写器运行得更快,但我不确定它是否能保证head = head->next 始终可以读取正确的值。
更新:如果在tail->next、n++ 之间添加原子操作会怎样,即,
void push(item *it) {
tail->next = it;
tail = it;
a.store(0, std::memory_order_release);
a.load(std::memory_order_acquire);
n++;
}
其中a 永远不会被读者访问?这会保证tail->next = it 和head = head->next 的顺序吗? (不过,它比使用 atomic n 运行得更快)
【问题讨论】:
-
在线程协调问题之外,在我看来,这段代码有几个问题。首先,当你完成节点时,你不能释放它们,因为最后一个消耗的节点必须保持活动状态才能保持队列有效。
-
其他问题:1)head = head->next;返回头;看起来像一个明显的错误,将来程序员将“修复”而没有意识到您的实现依赖于节点的异常延长寿命(这将很难或不可能使用原始指针实现)。 2) 当您遇到实现定义的 used 和 n 溢出行为时会发生什么? 3)如果你的作者让你的读者陷入困境(也许是不可能的)会发生什么?
-
volatile与线程无关,请改用原子类型或互斥锁。 -
@Jarod42 是什么让你说 volatile 不能用于线程?
-
"
a.load(std::memory_order_acquire);" 这到底是什么意思?你没有使用结果!
标签: c++ multithreading atomic volatile happens-before