condition_variable 条件变量
在C++中,condition_variable
是一种多线程同步机制,它允许一个或多个线程等待另一个线程发出通知,以便能够有效地进行线程同步1。condition_variable
是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待condition_variable
的条件成立而挂起;另一个线程使条件成立(给出条件成立信号)2。
condition_variable
的使用总是和一个互斥量结合在一起。它位于头文件<condition_variable>
下,包括condition_variable
和condition_variable_any
两种类型2。两者都能与std::mutex
一起使用。不同点在于,前者仅限于与 std::mutex
一起工作,而后者可以和任何满足最低标准的互斥量一起工作,从而加上了_any
的后缀。condition_variable_any
会产生额外的开销,一般只推荐使用condition_variable
2。
condition_variable
提供了两类操作:wait
和notify
3。这两类操作构成了多线程同步的基础。wait
函数有两种重载,一种只包含unique_lock
对象,另外一个包含Predicate
对象(等待条件)。notify_one
函数解锁正在等待当前条件的线程中的一个,如果没有线程在等待,则函数不执行任何操作。如果正在等待的线程多于一个,则唤醒的线程是不确定的3。
以下是一个使用condition_variable
的示例2:
#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() {
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {return ready;});
std::cout << "Worker thread is processing data\\n";
data += " after processing";
processed = true;
std::cout << "Worker thread signals data processing completed\\n";
lk.unlock();
cv.notify_one();
}
int main() {
std::thread worker(worker_thread);
data = "Example data";
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\\n";
}
cv.notify_one();
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {return processed;});
}
std::cout << "Back in main(), data = " << data << '\\n';
worker.join();
}
在以上的代码中,子线程先对互斥量进行加锁,在main()
函数中,主线程堵塞在对互斥量的加锁这里。子进程的中wait
函数对互斥量进行解锁,同时线程进入阻塞或者等待状态2。
在C++中,cv.notify_one();
是用来唤醒一个正在等待特定std::condition_variable
的线程1。如果有多个线程正在等待,notify_one()
只会唤醒其中一个线程23。其余的线程会继续保持阻塞状态,直到再次调用notify_one()
或者notify_all()
23。
这里需要注意的是,被唤醒的线程会尝试重新获取之前释放的互斥锁23。如果获取成功,线程会继续执行。如果获取失败(例如,其他线程已经持有了锁),那么这个线程会继续处于运行状态并尝试获取锁,而不会再次阻塞23。
以下是一个使用cv.notify_one();
的示例2:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
std::cout << "thread " << id << '\\n';
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_one();
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i)
threads[i] = std::thread(print_id, i);
go();
for (auto& th : threads) th.join();
return 0;
}
在这个例子中,cv.notify_one();
被用来唤醒一个正在等待cv
的线程2。当go()
函数被调用时,ready
变量被设置为true
,然后调用cv.notify_one();
来唤醒一个正在等待的线程2。被唤醒的线程会检查ready
变量,如果ready
为true
,则线程会继续执行2。如果ready
仍为false
,线程会再次等待2。