【C++并发编程】(四)条件变量

文章目录

  • (四)条件变量

(四)条件变量

条件变量(Condition Variable)用于线程间的同步,允许一个或多个线程在特定条件不满足时等待,并在条件满足时被其他线程唤醒。C++标准库中提供了的条件变量类std::condition_variable,其常用函数有:

  • std::condition_variable():默认构造函数

  • void notify_one(): 唤醒在该条件变量上等待的一个线程(如果有的话)。如果没有线程在等待,那么这个调用就没有效果。

  • void notify_all(): 唤醒在该条件变量上等待的所有线程。

  • void wait(std::unique_lock<std::mutex>& lock): 等待直到另一个线程调用该条件变量的 notify_one()notify_all()

以下例子展示std::condition_variable的使用:

例子1:使用notify_all唤醒所有线程

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

std::mutex mtx;             // 全局互斥量
std::condition_variable cv; // 全局条件变量
bool ready = false;         // 共享条件

void worker_thread() {
    std::unique_lock<std::mutex> lck(mtx);
    while (!ready) { // 如果条件不满足,则等待
        cv.wait(lck); // 释放锁并等待,直到被唤醒
    }
    // 当条件满足时,每个线程都执行一些工作(这里只是打印)
    std::cout << "Thread " << std::this_thread::get_id() << " is working\n";
}

void go_all() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true; // 设置条件为true
    cv.notify_all(); // 唤醒所有等待的线程
}

int main() {
    std::thread threads[5]; // 创建5个线程
    for (int i = 0; i < 5; ++i) {
        threads[i] = std::thread(worker_thread);
    }

    std::cout << "5 threads ready to work...\n";

    go_all(); // 唤醒所有线程

    for (auto& th : threads) {
        th.join();
    }

    return 0;
}

在这个例子中,我们创建了5个线程,每个线程都试图打印其ID。但是,这些线程首先会检查一个共享条件ready。如果readyfalse,线程会调用cv.wait(lck)进入等待状态,并释放它持有的互斥量mtx

go_all函数中的ready被设置为true,并且调用了cv.notify_all()时,所有等待的线程都会被唤醒,并重新尝试获取互斥锁以继续执行。

注意:std::lock_guard 不提供等待条件变量的机制。因此,在需要使用条件变量(std::condition_variable)的上下文中,需要使用 std::unique_lock

例子2:使用notify_one唤醒一个线程

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

std::mutex mtx;
std::condition_variable cv;
bool ready = false;
int task = 0; // 模拟任务,只有一个线程可以处理

void worker_thread() {
    std::unique_lock<std::mutex> lck(mtx);
    while (!ready) {
        cv.wait(lck); // 等待条件成立
    }
    // 执行任务(这里只是打印)
    std::cout << "Thread " << std::this_thread::get_id() << " is processing task " << task << std::endl;
    // 任务完成,重置条件
    ready = false;
    task++; // 下一个任务
}

void go() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true; // 设置条件为true
    cv.notify_one(); // 唤醒一个等待的线程
}

int main() {
    std::thread threads[5]; // 创建5个线程
    for (int i = 0; i < 5; ++i) {
        threads[i] = std::thread(worker_thread);
    }

    std::cout << "5 threads ready to work...\n";

    // 假设有3个任务需要处理
    for (int i = 0; i < 3; ++i) {
        go(); // 唤醒一个线程处理任务
        std::this_thread::sleep_for(std::chrono::seconds(1)); // 假设处理任务需要一些时间
    }

    for (auto& th : threads) {
        th.join();
    }

    return 0;
}

在这个例子中,每次调用go()函数时,都会唤醒一个等待的线程来处理任务。由于我们调用了go()三次,所以只会有三个线程被唤醒并处理任务。

相关推荐

  1. Golang 并发 Cond条件变量

    2024-05-05 04:00:01       32 阅读
  2. C++ 并发编程 | 并发世界

    2024-05-05 04:00:01       42 阅读
  3. C++ 并发编程 | 锁

    2024-05-05 04:00:01       26 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-05 04:00:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-05 04:00:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-05 04:00:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-05 04:00:01       20 阅读

热门阅读

  1. 1.Spring Security介绍

    2024-05-05 04:00:01       22 阅读
  2. Vue框架知识点表格总结

    2024-05-05 04:00:01       20 阅读
  3. 使用Spring Boot快速构建Spring应用

    2024-05-05 04:00:01       11 阅读
  4. linux定时运行脚本

    2024-05-05 04:00:01       13 阅读
  5. Python ansible 如何使用

    2024-05-05 04:00:01       11 阅读
  6. github.com/gin-contrib/timeout应前置使用

    2024-05-05 04:00:01       10 阅读
  7. 如何在 MySQL 中创建新用户并授予权限

    2024-05-05 04:00:01       12 阅读
  8. Docker容器管理详解

    2024-05-05 04:00:01       48 阅读