线程同步之条件变量--condition_variable


condition_variable简介

std::condition_variable是C++中用于线程同步的一个类。它通常与std::mutex一起使用,用于在一个或多个线程中阻塞,直到另一个线程修改了共享变量并通知了condition_variable。下面是一个例子,演示了如何使用std::condition_variable来实现线程间的通信:

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

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

    std::cout << "Worker thread is processing data" << std::endl;
    data += " after processing";
    processed = true;
    std::cout << "Worker thread signals data processing completed" << std::endl;

    lk.unlock();
    std::this_thread::sleep_for(std::chrono::seconds(5));
    cv.notify_one();
}

int main() {
    std::thread worker(work_thread);
    {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::lock_guard<std::mutex> lk(m);
        ready = true;
    }
    cv.notify_one();

    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, [] {return processed;});
    }
    std::cout << "Back in main, data = " << data << std::endl;

    worker.join();

    return 0;
}

/*
Worker thread is processing data
Worker thread signals data processing completed
Back in main, data =  after processing

[Done] exited with code=0 in 7.432 seconds
*/

在这个例子中,worker_thread等待ready变量为true,然后处理数据并通知主线程。主线程等待processed变量为true,然后打印处理后的数据。这个例子展示了std::condition_variable的基本用法。


成员函数

std::condition_variable是C++标准库中用于线程同步的类,它提供了以下成员函数:

  1. wait:阻塞当前线程,直到收到通知或超时。
    void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
    
    这个函数会在持有std::unique_lock锁的情况下,释放锁并将线程置于等待状态。当收到通知或超时时,线程会重新获得锁并继续执行。

在使用std::condition_variablewait函数时,可以正确地传递Predicate参数。wait函数有两个重载版本,其中第二个版本接受一个Predicate参数,用于判断条件是否满足。Predicate是一个可调用对象,通常是一个lambda表达式或者函数对象,用于在等待期间检查条件是否满足。

下面是一个示例,演示了如何在wait函数中正确地传递Predicate参数:

std::condition_variable cv;
std::mutex mtx;
bool dataReady = false;

void threadFunction() {
    std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck, []{ return dataReady; });
    // 线程被唤醒后,继续执行其他操作
}

void setDataReady() {
    std::lock_guard<std::mutex> lck(mtx);
    dataReady = true;
    cv.notify_one();
}

在这个示例中,cv.wait函数的第二个参数是一个lambda表达式[]{ return dataReady; },用于检查条件dataReady是否为true。当条件满足时,线程会被唤醒并继续执行。

因此,正确地传递Predicate参数就是在cv.wait函数中使用一个可调用对象(通常是lambda表达式或者函数对象),用于检查条件是否满足。

  1. notify_one:通知一个等待的线程。

    void notify_one();
    

    这个函数用于通知一个正在等待的线程,使其从等待状态中唤醒。

  2. notify_all:通知所有等待的线程。

    void notify_all();
    

    这个函数用于通知所有正在等待的线程,使它们从等待状态中唤醒。

这些成员函数可以与std::mutex一起使用,用于在一个或多个线程中阻塞,直到另一个线程修改了共享变量并通知了condition_variablewait函数会释放互斥锁,并在收到通知后重新获取互斥锁,从而实现线程的同步和通信。这些成员函数提供了一种有效的方式来协调多个线程的操作,以实现线程间的同步和通信。


实现线程间的通信

当使用std::condition_variable时,通常会结合使用std::mutex来实现线程间的通信。下面是一个实际的例子,演示了如何使用std::condition_variable来实现生产者-消费者模式,实现线程间的同步和通信。

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        {
            std::lock_guard<std::mutex> lk(mtx);
            data_queue.push(i);
            std::cout << "Produced: " << i << std::endl;
        }
        cv.notify_one();
    }
}

void consumer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lk(mtx);
        cv.wait(lk, [] { return !data_queue.empty(); });
        int data = data_queue.front();
        data_queue.pop();
        std::cout << "Consumed: " << data << std::endl;
    }
}

int main() {
    std::thread producer_thread(producer);
    std::thread consumer_thread(consumer);

    producer_thread.join();
    consumer_thread.join();

    return 0;
}

在这个例子中,producer线程向data_queue中推送数据,而consumer线程从data_queue中取出数据。std::condition_variable用于在consumer线程中等待,直到data_queue中有数据。这个例子展示了如何使用std::condition_variable来实现线程间的通信,以及如何在多线程环境中实现同步。

posted @ 2024-01-20 09:44  guanyubo  阅读(83)  评论(0编辑  收藏  举报