condition_variable 条件变量

发布时间 2023-12-12 21:00:46作者: ponder776

在C++中,condition_variable是一种多线程同步机制,它允许一个或多个线程等待另一个线程发出通知,以便能够有效地进行线程同步1condition_variable是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待condition_variable的条件成立而挂起;另一个线程使条件成立(给出条件成立信号)2

condition_variable的使用总是和一个互斥量结合在一起。它位于头文件<condition_variable>下,包括condition_variablecondition_variable_any两种类型2。两者都能与std::mutex一起使用。不同点在于,前者仅限于与 std::mutex 一起工作,而后者可以和任何满足最低标准的互斥量一起工作,从而加上了_any的后缀。condition_variable_any会产生额外的开销,一般只推荐使用condition_variable2

condition_variable提供了两类操作:waitnotify3。这两类操作构成了多线程同步的基础。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变量,如果readytrue,则线程会继续执行2。如果ready仍为false,线程会再次等待2