2

这段代码有竞争条件吗?

auto x = make_shared<Fun>(1984); //could also be raw ptr
auto t = thread(func, x);

Herb Sutter 在他的 C++ 和 Beyond 演讲中也使用了并发队列。

所以如果我有一个队列q

auto x  = new Fun(1984);
q.push(x);

//other thread 
auto ptr = q.pop();

这是比赛条件吗?另一个线程是否有可能弹出ptr并仍然看到ptr指向的内存位置的陈旧值?由于并发队列不在标准中,假设我使用的是 PPL/TBB 队列。

4

2 回答 2

3

在这两种情况下都没有。

如果不是针对std::thread. 编译器原则上允许重新排序移动,但是构造一个线程对象具有顺序一致性,这正式保证它可以工作。但是即使它没有那个属性,在实践中创建和启动一个线程也需要相当长的时间(执行一些移动指令的时间是几十万到几百万次),所以你实际上会(不是正式的,而是实际的)保证没有种族,即使没有顺序一致性(这个“实际保证”确实有些争议,在人为的极端情况下可能不成立,但形式保证无论如何都是真的)。

第二个示例使用并发队列,根据定义,该队列被设计为(使用锁或使用无锁算法)以不发生竞争条件的方式。1

在任何一种情况下,都保证最终在队列中的指针根本不存在(在这种情况下,pop操作将阻塞或失败,其中“失败”意味着消费线程知道没有可用的有效指针此时——它不会假设一些无效值)或者它处于有效状态。将指针添加到队列的原子(锁定或无锁)操作保证之前发生的对象构造也之前实现(即没有有效对象的队列上没有指针)。
这意味着当从队列中检索对象的指针时,该对象也必须有效(除非您作弊)。


1这显然假设了队列的正确操作,但这是一个公平的假设。

于 2013-08-25T14:18:19.557 回答
0

可能存在竞争条件,但前提x是当另一个线程开始使用它的副本时使用指针。

像这样的函数:

void CreateWork(Queue& q){
    auto x  = new Fun(1984);
    // could use x here
    q.push(x);
}

应该没有竞争条件,因为一旦x在队列中,调用的线程CreateWork就无法访问x.

于 2013-08-25T14:05:34.347 回答