【问题标题】:C++ Simple Consumer Producer IssueC++ 简单的消费者生产者问题
【发布时间】: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() 有机会抓住它之前立即再次抓住它。

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

【问题讨论】:

    标签: c++ multithreading concurrency


    【解决方案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 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
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      相关资源
      最近更新 更多