简体   繁体   English

std::condition_variable 和 std::mutex 是如何工作的?

[英]How std::condition_variable and std::mutex works exactly?

I'm reading this std::condition_variable example:我正在阅读这个std::condition_variable示例:

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
 
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
 
void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});
 
    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";
 
    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";
 
    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}
 
int main()
{
    std::thread worker(worker_thread);
 
    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();
 
    // wait for the worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';
 
    worker.join();
}

Let's focus on the beggining:让我们专注于开头:

std::thread worker(worker_thread);

here, we start the worked, which will lock the mutex immediately:在这里,我们开始工作,它将立即锁定互斥锁:

std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});

Then, we lock the mutex on main to change the value of ready然后,我们将互斥锁锁定在 main 上以更改ready的值

{
    std::lock_guard<std::mutex> lk(m);
    ready = true;
    std::cout << "main() signals data ready for processing\n";
}

but how is it possible that we even arrive at the line ready=true ?但是我们怎么可能到达ready=true行呢? The mutext m is blocked from the worked thread, so the line std::lock_guard<std::mutex> lk(m); mutext m被工作线程阻塞,所以行std::lock_guard<std::mutex> lk(m); will wait until the mutex m is unlocked.将等到互斥锁m解锁。 As I understand, when a mutex is locked and we try to lock it, we'll wait until it gets unlocked.据我了解,当互斥锁被锁定并且我们尝试锁定它时,我们将等到它被解锁。 However, it'll never get unlocked because the worked thread is waiting, therefore not releasing it.但是,它永远不会被解锁,因为工作线程正在等待,因此不会释放它。

In the link you have attached, note that the following在您附加的链接中,请注意以下内容

The wait operations atomically release the mutex and suspend the execution of the thread.等待操作以原子方式释放互斥体并暂停线程的执行。

Hence the line因此这条线

cv.wait(lk, []{return ready;});

releases the mutex and suspends the execution of the thread until the condition variable is notified, a timeout expires (with wit_for() ), or a spurious wake-up occurs, hence the thread is awakened, and the mutex is atomically reacquired释放互斥体并暂停线程的执行,直到通知条件变量、超时到期(使用wit_for() )或发生虚假唤醒,因此线程被唤醒,并且互斥体被原子地重新获取

Here's another example that will give you the gist of the mechanism.这是另一个示例,它将为您提供机制的要点。

#include <cstdio>                                                                                                                                                                                                   
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>

std::mutex mtx;
std::condition_variable cv;
bool signal = 0;

void A()
{
  while (1)
  {
    {
      std::unique_lock<std::mutex> lock(mtx);
      cv.wait(lock, [](){return signal;});
      signal = 0;
    }

    printf("Lock release from th A\n");
  }
}

int main()
{
  std::thread th(A);

  for (unsigned i = 0; i < 100; i++)
  {
    {
      std::lock_guard<std::mutex> lock(mtx);
      signal = 1;
    }

    cv.notify_one();
    printf("Sending signal %i\n", i);
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }

  th.join();
  return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM