2017-04-13 65 views
3

我有一个非常简单的C++ produer消费者线程的代码,但我打印的“Hello World”C++简单的消费生产者问题

我想要什么下面的代码打印是这样的:

“HelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorld”

condition_variable mcond; // the variable communicating events 
mutex mmutex; // the locking mechanism 

void hello() 
{ 
    while (true) { 
     unique_lock<mutex> lck{ mmutex }; // acquire mmutex 
     mcond.wait(lck); /* do nothing */; // release lck and wait; 
               // re-acquire lck upon wakeup 
     cout << "Hello"; 

     lck.unlock(); 

    } 
} 

void world() 
{ 
    while (true) 
    { 
     unique_lock<mutex> lck{ mmutex }; // protect operations 

     cout << "World"; 
     mcond.notify_one(); 
    } 
} 

int main() 
{ 
    thread t1{ hello }; 
    thread t2{ world }; 

    t1.join(); 
    t2.join(); 

    return 0; 
} 

上面的代码是什么是印刷是这样的:

“WorldWorldWorldWorldWorldWorldWorldWorldWorld 你好 WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorld 你好 WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldHelloWorldWorldWorldWorldWorld”

我怀疑它不是在同步打印的原因是因为世界()函数释放锁,并立即再次抓住它在hello()之前有机会抓住它。

我不知道如何解决这个问题。我如何正确设置线程同步?

回答

5

线程本质上是不同步所以不知道一个线程在另一个线程在CPU时间获得机会之前会运行多长时间。

如果您想要严格订购到您的输出,那么你将不得不做到这一点。一种方式是一个标志来判断哪些需要下一个要打印的字的每个线程:

// avoid using global information 
struct hello_world_control 
{ 
    std::condition_variable cv; 
    std::mutex mtx; 
    bool do_hello = true; // start with "Hello" 

    // make this atomic to avoid having to lock it 
    std::atomic_bool done{false}; 
}; 

void hello(hello_world_control& ctrl) 
{ 
    // setting ctrl.done = true; will end the thread 
    while(!ctrl.done) 
    { 
     // start a new scope for the lock 
     { 
      std::unique_lock<std::mutex> lock{ctrl.mtx}; 

      // wait until do_hello become true 
      ctrl.cv.wait(lock, [&]{ return ctrl.do_hello; }); 

      std::cout << " Hello"; 
      ctrl.do_hello = false; // signal hello has been done 
     } 
     // when the scope ends the lock is released 

     ctrl.cv.notify_one(); // tell the waiting thread 
    } 
} 

void world(hello_world_control& ctrl) 
{ 
    while(!ctrl.done) 
    { 
     { 
      std::unique_lock<std::mutex> lock{ctrl.mtx}; 

      // wait until do_hello become false 
      ctrl.cv.wait(lock, [&]{ return !ctrl.do_hello; }); 

      std::cout << " World"; 
      ctrl.do_hello = true; // signal hello now needs to happen 
     } 

     ctrl.cv.notify_one(); // tell the waiting thread 
    } 
} 

int main() 
{ 
    hello_world_control ctrl; 

    // use std::ref() to pass ctrl by reference to each thread 
    std::thread t1{hello, std::ref(ctrl)}; 
    std::thread t2{world, std::ref(ctrl)}; 

    // let threads run for 100 milliseconds 
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); 

    // signal threads to stop looping 
    ctrl.done = true; 

    // synchronize with main thread 
    t1.join(); 
    t2.join(); 
} 

输出:

Hello World Hello World Hello World 
Hello World Hello World Hello World 
Hello World Hello World Hello World 
...