【问题标题】:std::C++ Can reading and writing asynchronously in non empty queue lead to race condition?std::C++ 在非空队列中异步读写会导致竞争条件吗?
【发布时间】:2020-11-25 01:31:17
【问题描述】:

我将std::queue 用于发布-订阅类型系统。

  • 主线程将一些数据推入队列并继续(这里没有互斥锁)
// no need to acquire any lock as only the main thread inserts in the queue
queue.push(dataToLog);    
// notify the consumer thread waiting on this new available data
conditionalVariable.notify_one();
  • 设置条件变量时工作线程拉取数据
std::unique_lock<std::mutex> locker(queueMutex);
    
// put the thread to sleep till the thread is not notified in the producer code and queue is empty
conditionalVariable.wait(locker, []() {return !queue.empty();});
    
// get the data once it is available
const data * latestData = queue.front();
queue.pop();
locker.unlock();

我的问题是,考虑到在将数据放入队列时没有锁这一事实,这种线程安全编码是否安全。请注意,有一个检查 conditionalVariable.wait(locker, []() {return !queue.empty();}); 以确保当队列为空时消费者不会弹出任何内容。但是可能会出现主线程写,工作线程同时拉出的情况。这是否被视为竞争条件?我的困惑源于这样一个事实,即使队列是主线程和工作线程之间的共享变量,但它们访问的实际数据,即队列的前面和后面实际上并没有共享。

我应该在将数据放入队列的同时放置锁吗?

只有一个线程写入队列,并且只有一个线程(不同于写入的线程)从队列中读取。

【问题讨论】:

  • 这与队列无关,与条件变量的工作方式有关。你总是获得一个修改锁。

标签: c++ multithreading mutex producer-consumer


【解决方案1】:

是的,尝试同时执行 pushpop 似乎是一种竞争条件。

不管队列的前面和后面是否实际共享,(取决于他们选择如何实现它)队列可能很容易有一些内部变量被pushpop,因此同时执行它们会导致问题。

标准中的确切措辞是:

如果程序的执行包含两个潜在的并发冲突操作,则程序的执行包含数据竞争,其中至少一个不是原子的,并且两者都不会在另一个之前发生,除了下面描述的信号处理程序的特殊情况。任何此类数据竞争都会导致未定义的行为。

除非您能找到可以说pushpop 都是原子的(我没有看到),否则您正在执行两个潜在的并发冲突操作,这两个操作都不是原子的。因此,您似乎有未定义的行为。

【讨论】:

    猜你喜欢
    • 2023-03-11
    • 1970-01-01
    • 2021-09-03
    • 2014-02-21
    • 2015-05-21
    • 2017-03-20
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    相关资源
    最近更新 更多