C++ 简单的消费者生产者问题

Posted

技术标签:

【中文标题】C++ 简单的消费者生产者问题【英文标题】:C++ Simple Consumer Producer Issue 【发布时间】:2017-04-13 02:38:48 【问题描述】:

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

我想要打印以下代码是这样的:

“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;

上面的代码打印的是这样的:

“世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界世界

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

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

【问题讨论】:

【参考方案1】:

线程本质上是不同步的,因此不知道一个线程将运行多长时间,另一个线程在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 donefalse;
;

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> lockctrl.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> lockctrl.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 t1hello, std::ref(ctrl);
    std::thread t2world, 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
...

【讨论】:

以上是关于C++ 简单的消费者生产者问题的主要内容,如果未能解决你的问题,请参考以下文章

c++生产者和消费者问题

条件变量 + 互斥体 + pthreads 的 C++ 生产者消费者问题

用c语言或c++编写编程实现生产者消费者或读写者的同步问题

c++并发练习---生产者消费者模型

C++实现生产者和消费者模型

C++实现 生产者消费者模型