【问题标题】:Not able to set conditional Variable无法设置条件变量
【发布时间】:2020-11-05 17:56:32
【问题描述】:

在下面的代码中,我在函数waitingForWork() 中等待条件变量,但从未调用过doTheCleanUp()

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <iostream>           // std::cout
#include <thread>          // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable


std::mutex mtx;
std::condition_variable cv;
bool stop=false;

void stopTheWait()
{
    sleep(5);
    printf("stopping the wait.. \n\n");
    std::lock_guard<std::mutex> lck(mtx);
    stop = true;
    cv.notify_all();
}

void doTheCleanUp()/* is never called*/ {
    printf("clean up... \n\n");
}

void waitingForWork(){
    printf("wait for ever... \n\n");

    std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck, []{ return stop;});
    doTheCleanUp();
    printf("clean Up Done, now end wait... \n\n");
}


int main()
{
    printf("in main... \n");
   
   std::unique_lock<std::mutex> lck(mtx);

   std::thread t1(stopTheWait);
   
   waitingForWork();
   
   printf("exiting main...\n");
   sleep(1);
   
   return 0;
}

【问题讨论】:

  • 仅供参考:这些 C 头文件的 C++ 版本名为 cstdiocstdlibcsignal。更喜欢使用它们。

标签: c++ c++11 condition-variable


【解决方案1】:

main() 正在锁定std::mutex,然后在同一个线程中调用waitingForWork(),这会再次尝试锁定std::mutexThis is undefined behavior:

如果lock 由已经拥有互斥锁的线程调用,行为未定义:例如,程序可能死锁。鼓励可以检测到无效使用的实现抛出带有错误条件resource_deadlock_would_occurstd::system_error 而不是死锁。

main() 没有充分的理由获得该初始锁,摆脱它:

int main()
{
    printf("in main... \n");
   
   //std::unique_lock<std::mutex> lck(mtx); // <-- HERE

   std::thread t1(stopTheWait);
   
   waitingForWork();
   
   printf("exiting main...\n");
   sleep(1);
   
   return 0;
}

注意,一般来说,如果你必须在同一个线程中多次锁定一个互斥体,你需要使用std::recursive_mutex来代替:

调用线程在成功调用locktry_lock 时开始拥有recursive_mutex在此期间,线程可能会对locktry_lock 进行额外调用。当线程对unlock 进行匹配次数的调用时,所有权期限结束。


还要注意,你需要在t1超出范围并被销毁之前调用t1.join()t1.detach(),否则它的destructor会中止调用进程:

如果 *this 有关联的线程 (joinable() == true),则调用 std::terminate()

【讨论】:

  • 自动连接的 C++20 std::jthread 可能值得一提。
  • 主线程必须获得锁(在线程之前)并保持它直到它调用等待。否则线程可能先到达notify_all,然后主线程就会卡住。
  • what if notify() is called before wait()?。如果main() 需要在创建thread 时锁定互斥锁,则需要在调用waitingForWork() 之前解锁互斥锁。
【解决方案2】:

你这里有一个错误:

void waitingForWork(){
    printf("wait for ever... \n\n");

    std::unique_lock<std::mutex> lck(mtx);         // This lock is bad.
                                                   // you already locked the
                                                   // mutex in main.
                                                   //
                                                   // locking it again is UB

    cv.wait(lck, []{ return stop;});               // Once you enter wait()
                                                   // lock will be released
                                                   // until you are notified.
    doTheCleanUp();
    printf("clean Up Done, now end wait... \n\n");
}

【讨论】:

    猜你喜欢
    • 2021-06-28
    • 2011-12-28
    • 2020-12-14
    • 2013-06-13
    • 2022-01-17
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多