自学内容网 自学内容网

C++ 条件变量:wait、wait_for、wait_until

前言

在C++中,条件变量(std::condition_variable)是用来在多个线程之间同步执行流的一种机制。它们通常与互斥锁(如std::mutex)一起使用,以在特定条件满足时唤醒一个或多个线程。条件变量有三种使线程阻塞并等待唤醒的方法,分别是waitwait_forwait_until三种方式,三种方式有不同的特点;

内容

Wait

  • 功能wait 函数使当前线程阻塞,直到另一个线程调用 notify_onenotify_all
  • 参数:它需要两个参数:一个 std::unique_lock<std::mutex>(或类似的锁类型),它应该在调用 wait 之前由调用线程锁定,并且在 wait 等待期间由 wait 自动解锁;以及一个函数或可调用对象(通常是一个lambda表达式或函数指针),用于检查条件是否满足。
  • 特点wait 会无限期地等待,直到条件满足。它会在每次从 wait 返回时重新获取互斥锁。
#include <mutex>
#include <condition_variable>
#include <thread> 

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); // 等待ready变为true 
}
// 当ready为true时,继续执行... 
std::cout << "Thread " << id << '\n'; 
} 

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

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

std::cout << "10 threads ready to race...\n";
go(); // 唤醒所有线程 

// 等待所有线程完成 
for (auto& th : threads) 
{
th.join(); 
return 0; 
}
}

Wait_for

  • 功能wait_for 函数使当前线程阻塞一段指定的时间或直到另一个线程调用 notify_onenotify_all,以先发生者为准。
  • 参数:与 wait 类似,它需要一个 std::unique_lock<std::mutex> 和一个函数或可调用对象来检查条件。此外,它还需要一个表示等待时间的 std::chrono::duration 类型的参数。
  • 特点wait_for 提供了等待时间的上限。如果在指定的时间内条件没有变为真,则 wait_for 会返回,即使 notify_onenotify_all 还没有被调用。
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 
#include <chrono> 
std::mutex mtx; 
std::condition_variable cv; 
bool ready = false; 
void print_id(int id) 
{ 
std::this_thread::sleep_for(std::chrono::seconds(1)); 
std::cout << "Thread " << id << '\n'; 
} 
void print_ready() 
{ 
std::unique_lock<std::mutex> lck(mtx); 
while (!ready) 
{ 
// 循环直到条件满足 
cv.wait_for(lck, std::chrono::seconds(2), []{ return ready; }); 
// 等待直到ready为true或超时 
} 
std::cout << "Ready now\n"; 
} 

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

int main() 
{ 
std::thread threads[10]; 
// 启动10个线程,它们将等待ready标志 
for (int i = 0; i < 10; ++i) 
threads[i] = std::thread(print_ready); 
std::cout << "10 threads ready to race...\n";
std::thread producer(go); 
// 等待所有线程完成 
for (auto& th : threads) 
th.join(); 
producer.join(); 
return 0;
}

Wait_until

  • 功能wait_until 函数使当前线程阻塞直到指定的时间点或直到另一个线程调用 notify_onenotify_all,以先发生者为准。
  • 参数:与 waitwait_for 类似,它需要一个 std::unique_lock<std::mutex> 和一个函数或可调用对象来检查条件。此外,它还需要一个表示未来某个时间点的 std::chrono::time_point 类型的参数。
  • 特点wait_until 允许指定一个绝对的时间点作为等待的结束条件。如果在指定的时间点之前条件没有变为真,则 wait_until 会返回,即使 notify_onenotify_all 还没有被调用。
#include <iostream>  
#include <thread>  
#include <mutex>  
#include <condition_variable>  
#include <chrono>  
#include <system_clock>  
  
std::mutex mtx;  
std::condition_variable cv;  
bool ready = false;  

void print_id(int id, const std::string& threadName) {  
    // 模拟一些工作  
    std::this_thread::sleep_for(std::chrono::seconds(1));  
    std::cout << threadName << " " << id << std::endl;  
}  
  
void wait_for_ready(int id, const std::string& threadName) {  
    std::unique_lock<std::mutex> lck(mtx);  
    auto future_time = std::chrono::system_clock::now() + std::chrono::seconds(5); // 等待最多5秒  
  
    while (!ready) {  
        if (cv.wait_until(lck, future_time) == std::cv_status::timeout) {  
            std::cout << threadName << " " << id << " Timeout! Exiting.\n";  
            return;  
        }  
    }  
  
    // 如果ready为true,则继续执行  
    std::cout << threadName << " " << id << " Ready now.\n";  
    // 可以在这里处理数据...  
}  
  
void go() {  
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 生产者准备数据需要一些时间  
  
    {  
        std::unique_lock<std::mutex> lck(mtx);  
        ready = true;  
        cv.notify_all(); // 唤醒所有等待的线程  
    }  
  
    // 生产者可以继续执行其他任务...  
}  
  
int main() {  
    std::thread threads[10];  
  
    // 启动10个消费者线程  
    for (int i = 0; i < 10; ++i) {  
        threads[i] = std::thread(wait_for_ready, i, "Consumer " + std::to_string(i+1));  
    }  
  
    std::thread producer(go);  
  
    // 等待所有消费者线程完成  
    for (auto& th : threads) {  
        th.join();  
    }  
  
    producer.join();  
  
    return 0;  
}

总结

  • wait:无限期等待直到条件满足。
  • wait_for:等待直到条件满足或指定的时间过去。
  • wait_until:等待直到条件满足或指定的时间点到达。

原文地址:https://blog.csdn.net/m0_64240990/article/details/142346774

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!