C++ 互斥是从不同的线程访问外部变量所必需的吗?

C++ 互斥是从不同的线程访问外部变量所必需的吗?,c++,multithreading,qt,mutex,C++,Multithreading,Qt,Mutex,我正在用Qt/C++开发一个应用程序。在某些情况下,有两个线程:一个是UI线程,另一个是后台线程。我必须根据外部变量的值从后台线程执行一些操作,该变量的类型为bool。我通过单击UI上的按钮来设置此值 标题.cpp extern bool globalVar; //main ui thread on button click setVale(bool val){ globalVar = val; } while(1){ if(globalVar) //do some oper

我正在用Qt/C++开发一个应用程序。在某些情况下,有两个线程:一个是UI线程,另一个是后台线程。我必须根据外部变量的值从后台线程执行一些操作,该变量的类型为
bool
。我通过单击UI上的按钮来设置此值

标题.cpp

extern bool globalVar;
//main ui thread on button click
setVale(bool val){
 globalVar = val;
}
 while(1){
  if(globalVar)
    //do some operation
  else
    //do some other operation
  }
main window.cpp

extern bool globalVar;
//main ui thread on button click
setVale(bool val){
 globalVar = val;
}
 while(1){
  if(globalVar)
    //do some operation
  else
    //do some other operation
  }
backgroundThread.cpp

extern bool globalVar;
//main ui thread on button click
setVale(bool val){
 globalVar = val;
}
 while(1){
  if(globalVar)
    //do some operation
  else
    //do some other operation
  }
在这里,只有当用户单击按钮时才会写入
globalVar
,而读取是连续进行的

所以我的问题是:

  • 在上述情况下,互斥是强制性的吗
  • 如果读写同时发生,是否会导致应用程序崩溃
  • 如果读取和写入同时发生,
    globalVar
    是否将具有除
    true
    false
    以外的值
  • 最后,操作系统是否提供了任何类型的锁定机制来防止读/写操作同时通过不同的线程访问内存位置

  • 因为它只是一个简单的布尔值,我认为互斥是多余的,所以你应该选择一个原子整数。原子将在单个CPU时钟中读取和写入,因此无需担心,而且它将是无锁的,如果可能,这总是更好的

    如果是更复杂的东西,那么一定要使用互斥

    它不会因此而崩溃,但您可能会导致数据损坏,这可能会使应用程序崩溃

    系统不会为您管理这些内容,您可以手动操作,只需确保所有数据访问都通过互斥锁即可

    编辑:

    由于您多次指定了不需要复杂解决方案的情况,因此可以选择简单地使用互斥体而不是bool。没有必要使用互斥来保护bool,因为可以将互斥用作bool,是的,可以使用原子,但互斥已经做到了这一点(加上递归互斥的一些额外功能)

    您的确切工作量是多少也很重要,因为您的示例在实践中没有多大意义。了解这些
    操作是什么将很有帮助

    因此,在您的ui线程中,您可以简单地
    val?mutex.lock():mutex.unlock()
    ,在辅助线程中,如果(mutex.tryLock())doStuff,则可以使用
    ;mutex.unlock();其他的东西。现在,如果次线程中的操作花费的时间太长,而您恰好更改了主线程中的锁,那么将阻塞主线程,直到次线程解锁。您可以在主线程中使用
    tryLock(timeout)
    ,具体取决于您的喜好,
    lock()
    将阻塞直到成功,而
    tryLock(timeout)
    将阻止阻塞,但锁可能会失败。另外,注意不要从锁定线程以外的线程解锁,也不要解锁已解锁的互斥锁


    根据您实际执行的操作,异步事件驱动方法可能更合适。当(1)
    时,您真的需要它吗?您执行这些操作的频率是多少?

    因为它只是一个简单的布尔值,我认为互斥是多余的,所以您应该选择原子整数。原子将在单个CPU时钟中读取和写入,因此无需担心,而且它将是无锁的,如果可能,这总是更好的

    如果是更复杂的东西,那么一定要使用互斥

    它不会因此而崩溃,但您可能会导致数据损坏,这可能会使应用程序崩溃

    系统不会为您管理这些内容,您可以手动操作,只需确保所有数据访问都通过互斥锁即可

    编辑:

    由于您多次指定了不需要复杂解决方案的情况,因此可以选择简单地使用互斥体而不是bool。没有必要使用互斥来保护bool,因为可以将互斥用作bool,是的,可以使用原子,但互斥已经做到了这一点(加上递归互斥的一些额外功能)

    您的确切工作量是多少也很重要,因为您的示例在实践中没有多大意义。了解这些
    操作是什么将很有帮助

    因此,在您的ui线程中,您可以简单地
    val?mutex.lock():mutex.unlock()
    ,在辅助线程中,如果(mutex.tryLock())doStuff,则可以使用
    ;mutex.unlock();其他的东西。现在,如果次线程中的操作花费的时间太长,而您恰好更改了主线程中的锁,那么将阻塞主线程,直到次线程解锁。您可以在主线程中使用
    tryLock(timeout)
    ,具体取决于您的喜好,
    lock()
    将阻塞直到成功,而
    tryLock(timeout)
    将阻止阻塞,但锁可能会失败。另外,注意不要从锁定线程以外的线程解锁,也不要解锁已解锁的互斥锁

    根据您实际执行的操作,异步事件驱动方法可能更合适。当(1)
    时,您真的需要它吗?您多久执行一次这些操作?

    循环

    while(1){
       if(globalVar)
          //do some operation
       else
          //do some other operation
    }
    
    是,非常浪费。因此,您最好使用一些经典的同步,当有事情要做时,这些同步将唤醒后台线程(大部分)。你应该考虑适应。

    假设您从以下内容开始:

    #include <thread>
    #include <mutex>
    #include <condition_variable>
    
    std::mutex m;
    std::condition_variable cv;
    bool ready = false;
    
    #包括
    #包括
    #包括
    std::互斥m;
    std::条件变量cv;
    bool ready=false;
    
    您的工作线程可以是这样的:

    void worker_thread()
    {
        while(true)
        {
            // Wait until main() sends data
            std::unique_lock<std::mutex> lk(m);
            cv.wait(lk, []{return ready;});
    
            ready = false;
    
            lk.unlock();
    }
    
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
    }
    cv.notify_one();
    
    void worker\u thread()
    {
    while(true)
    {
    //等待main()发送数据
    std::唯一锁lk(m);
    cv.wait(lk,[{return ready;});
    就绪=错误;