c – 在这个简单的场景中是否可能出现死锁?

请参阅以下代码:

std::mutex mutex;
std::condition_variable cv;
std::atomic<bool> terminate;

// Worker thread routine
void work() {
    while( !terminate ) {
        {
            std::unique_lock<std::mutex> lg{ mutex };
            cv.wait(lg);

            // Do something
        }
        // Do something
    }
}

// This function is called from the main thread
void terminate_worker() {
    terminate = true;
    cv.notify_all();
    worker_thread.join();
}

是否可能发生以下情况?

>工作者线程正在等待信号.
>主线程名为terminate_worker();

>主线程将原子变量terminate设置为true,然后发信号通知工作线程.
>工作线程现在醒来,完成工作并从终止加载.在此步骤中,尚未看到由主线程进行的终止更改,因此工作线程决定等待另一个信号.

>现在发生僵局……

我想知道这是可能的.据我所知,std :: atomic只保证没有竞争条件,但内存顺序是另一回事.问题:

>这可能吗?
>如果这是不可能的,如果终止不是原子变量而只是bool,这是否可能?或者原子性与此无关?
>如果可以,我该怎么办?

谢谢.

最佳答案 我不相信,你所描述的是可能的,因为cv.notify_all()afaik(如果我错了请纠正我)与wait()同步,所以当工作线程唤醒时,它会看到更改终止.

然而:

死锁可以通过以下方式发生:

>工作线程(WT)确定终止标志仍为false.
>主线程(MT)设置终止标志并调用cv.notify_all().
>因为没有人正在等待条件变量,通知被“丢失/忽略”.
> MT调用join和blocks.
> WT进入睡眠状态(cv.wait())并阻止.

解:

虽然您在调用cv.notify时不必按住锁定,但是

>当你修改终止时,必须持有一个锁(即使它是一个原子)
>必须确保在持有相同的锁时检查条件和实际的等待调用.

这就是为什么有一种等待形式在它将线程发送到睡眠之前执行此检查的原因.

更正的代码(具有最小的更改)可能如下所示:

// Worker thread routine
void work() {
    while( !terminate ) {
        {
            std::unique_lock<std::mutex> lg{ mutex };
            if (!terminate) {
                cv.wait(lg);
            }

            // Do something
        }
        // Do something
    }
}

// This function is called from the main thread
void terminate_worker() {
    {
        std::lock_guard<std::mutex> lg(mutex);
        terminate = true;
    }
    cv.notify_all();
    worker_thread.join();
}
点赞