Man*_*ker 3 c++ concurrency multithreading
我有一个非常简单的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;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码是什么打印是这样的:
"WorldWorldWorldWorldWorldWorldWorldWorldWorld 你好 WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorld 你好 WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldHelloWorldWorldWorldWorldWorld"
我怀疑它不是同步打印的原因是因为world()函数正在释放锁并在hello()有机会抓住之前立即再次抓取它.
我不知道如何解决这个问题.如何正确设置线程同步?
线程本质上是不同步的,所以没有人知道一个线程会在另一个线程获得机会之前运行多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();
}
Run Code Online (Sandbox Code Playgroud)
输出:
Hello World Hello World Hello World
Hello World Hello World Hello World
Hello World Hello World Hello World
...
Run Code Online (Sandbox Code Playgroud)