2017-04-10 46 views
4

我的问题是基于以下的C++代码C++:与std :: lock_guard`互斥是否足以同步两个`std :: thread`s?

#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; 
} 

样品这更是一个问题,让我认识不明确,而&得到std::condition_variable样本使用IFF需要。

我有2个C++ std::thread s在main方法启动。它的一个控制台应用程序osx。所以使用clang编译它。这两个线程使用通用对象 ClassUtility来调用一个方法来完成一些繁重的任务。对于这个示例代码来解释这种情况,只有当 应用程序关闭时,即当我在控制台上按ctrl+c时,这两个线程才会运行无限循环&关闭。

寻求认识:

它是正确的,如果我强行使用std::lock_guardstd::mutex同步或保护到ClassUtilitycommon_obejct的呼吁。不知何故,我似乎 陷入困境与这个“只是一个互斥方法”。如果我使用互斥锁锁定循环,则线程都不会启动。而且,我有时会遇到段错误。这是因为他们是lambda? 分配给每个线程?

使用2个线程之间的std::condition_variable还是使用lambda表示信号&同步它们会更好?如果是的话,那么std::condition_variable如何在这里使用 之间的lambda?

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

+1

这应该工作得很好。你怎么知道“没有任何线索开始?”你可以通过独立于共享状态的东西(比如每个线程写入自己的文件而不是共享'std :: cout')来测试它吗? – Angew

+0

另外,请注意,这里为并行性(甚至是线程切换)留下了很小的空间,因为互斥锁在睡眠期间保持锁定状态。 – Angew

+1

如果你有代码,你会遇到死锁或饥饿或段错误,为什么地球上你发布的简化代码不? – paddy

回答

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(); 
} 

基本上等同于:

{ 
    g_mutex.lock(); 
    std::cout << "worker_thread_1 looping" << std::endl; 
    g_common_object.do_something(); 
    g_mutex.unlock(); 
} 

情况除外:

  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. 
    } 
} 

我想你正在尝试编写的实际代码确实有并行的实际操作;只是要记住一件事。不需要

条件变量

条件变量是当你需要一个线程等待,直到另一个线程做一些具体的事情。在这里,您只是确保两个线程不会同时修改对象,因此mutex已足够且适合。

1

你的代码永远不会终止,除非我不能错。

正如其他人指出的那样,它提供了几乎没有并行机会的机会,因为长时间睡眠会发生在互斥锁锁定到睡眠线程中。

下面是一个简单的版本,它通过在循环中放置任意的有限极限来终止。

也许你还没有明白join()是做什么的? 它是当前线程(执行join()),直到连接线程结束。但是,如果它不结束目前的线程。

#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 (int i=0;i<10;++i) { 

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

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


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

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

     for (int i=0;i<10;++i) { 

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

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


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

    return 0; 
} 
相关问题