C++:使用`std :: lock_guard`的互斥量足以同步两个`std :: thread`s?

Gam*_*ads 4 c++ lambda multithreading c++11

我的问题是基于下面的C++代码示例

#include <chrono>
#include <thread>
#include <mutex>
#include <iostream>

class ClassUtility
{
public:
    ClassUtility() {}
    ~ClassUtility() {}

    void do_something() {
      std::cout << "do something called" << std::endl;

      using namespace std::chrono_literals;
      std::this_thread::sleep_for(1s);
    }
};


int main (int argc, const char* argv[]) {

  ClassUtility g_common_object;

  std::mutex  g_mutex;

  std::thread worker_thread_1([&](){

      std::cout << "worker_thread_1 started" << std::endl;

      for (;;) {

          std::lock_guard<std::mutex> lock(g_mutex);

          std::cout << "worker_thread_1 looping" << std::endl;
          g_common_object.do_something();
      }
  });


  std::thread worker_thread_2([&](){

      std::cout << "worker_thread_2 started" << std::endl;

      for (;;) {

          std::lock_guard<std::mutex> lock(g_mutex);

          std::cout << "worker_thread_2 looping" << std::endl;
          g_common_object.do_something();
      }
  });


  worker_thread_1.join();
  worker_thread_2.join();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这更像是一个问题,让我的理解清晰,并获得std::condition_variableiff所需的样本用法.

我有2个C++ std::thread,它以main方法启动.它是一个控制台应用程序osx.所以用clang编译它.两个线程都使用一个共同的对象 ClassUtility来调用一个方法做一些繁重的任务.对于这个示例代码来解释这种情况,两个线程都运行无限循环并仅在应用程序关闭时关闭,即当我按下ctrl+c控制台时.

寻求知道:

如果我使用std::lock_guardon std::mutex来同步或保护对common_obejctof 的调用,这是否正确ClassUtility?不知何故,我似乎遇到了这个" 只是一个互斥方法 "的麻烦.如果我使用互斥锁锁定循环,则没有任何线程启动.而且,我有时会遇到段错误.这是因为他们是lambdas吗?分配给每个线程?

std::condition_variable在两个线程或lambda之间使用它来发信号并同步它们会更好吗?如果是,那么如何std::condition_variable在lambda之间使用?

注意:由于问题只是寻求信息,因此这里提供的代码可能无法编译.它只是提供一个真实的场景

Jan*_*dec 8

你的代码是安全的

请记住,lock_guard只是调用.lock()并将调用注入到.unlock()块的末尾.所以

{
    std::lock_guard<std::mutex> lock(g_mutex);
    std::cout << "worker_thread_1 looping" << std::endl;
    g_common_object.do_something();
}
Run Code Online (Sandbox Code Playgroud)

基本上相当于:

{ 
    g_mutex.lock();
    std::cout << "worker_thread_1 looping" << std::endl;
    g_common_object.do_something();
    g_mutex.unlock();
}
Run Code Online (Sandbox Code Playgroud)

除了:

  1. 即使通过异常并且阻止了块,也会调用解锁
  2. 它确保你不会忘记给它打电话.

您的代码不是并行的

你是相互排除每个线程中的所有循环体.没有什么可以让两个线程实际上并行进行.使用线程的要点是,每个对象可以处理单独的对象集(并且只读取公共对象),因此不必锁定它们.

在示例代码中,你真的应该锁定通用对象的工作; std::cout它本身就是线程安全的.所以:

{ 
    std::cout << "worker_thread_1 looping" << std::endl;
    {
        std::lock_guard<std::mutex> lock(g_mutex);
        g_common_object.do_something();
        // unlocks here, because lock_guard injects unlock at the end of innermost scope.
    }
}
Run Code Online (Sandbox Code Playgroud)

我想你想写的实际代码确实有并行实际做的事情; 只是要记住一件事.

不需要条件变量

条件变量适用于需要一个线程等待另一个线程执行某些特定操作的情况.在这里,您只需要确保两个线程不会同时修改对象,这样mutex就足够了.