C++并发之条件变量(std::condition_variable)

2024-06-15 19:04

本文主要是介绍C++并发之条件变量(std::condition_variable),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1 概述
  • 2 使用实例
  • 3 接口使用
    • 3.1 wait
    • 3.2 wait_for
    • 3.3 wait_until
    • 3.4 notify_one
    • 3.5 notiry_all
    • 3.5 notify_all_at_thread_exit

1 概述

  条件变量是一个能够阻塞调用线程直到被通知恢复的对象。
  当调用其中一个等待函数时,它使用unique_lock(通过互斥锁)来锁定线程。线程保持阻塞状态,直到被另一个调用同一condition_variable对象上的通知函数的线程唤醒。
  条件变量类型的对象总是使用unique_lock来等待.
其类图如下:
类图

2 使用实例

struct Function4NotiryAll
{bool is_ready = false;std::mutex mutex;std::condition_variable cv;int counter = 0;void print_id(int id){std::unique_lock<std::mutex> lock(mutex);while(!is_ready)cv.wait(lock);std::cerr << "id:" << id << std::endl;counter++;}void go(){std::unique_lock<std::mutex> lock(mutex);is_ready = true;cv.notify_all();}
};void ConditionVariableSuite::notiry_all()
{std::thread threads[10];Function4NotiryAll function;for(int i = 0; i < 10; ++i)threads[i] = std::thread(&Function4NotiryAll::print_id, std::ref(function), i);function.go();for(auto & thread : threads)thread.join();TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3 接口使用

3.1 wait

struct Function4Wait
{volatile int cargo = 0;int counter = 0;std::mutex mutex;std::condition_variable cv;inline bool have_cargo() { return cargo != 0; }inline void consume_cargo() { cargo = 0; }void consume(int n){for(int i = 0; i < n; i++){std::unique_lock<std::mutex> lock(mutex);while(!have_cargo())cv.wait(lock);std::cerr << "cargo: " << cargo << std::endl;counter++;consume_cargo();}}void consume_with_predicate(int n){for(int i = 0; i < n; i++){std::unique_lock<std::mutex> lock(mutex);cv.wait(lock, std::bind(&Function4Wait::have_cargo, this));std::cerr << "cargo: " << cargo << std::endl;counter++;consume_cargo();}}inline void product(int n){std::unique_lock<std::mutex> lock(mutex);cargo = n;cv.notify_one();}
};void ConditionVariableSuite::wait()
{Function4Wait function;  std::thread thread[2];int n = 10;thread[0] = std::thread(&Function4Wait::consume, std::ref(function), 10);for(int i = 0; i < n; i++){while(function.have_cargo())std::this_thread::yield();function.product(i + 1);}thread[0].join();TEST_ASSERT_EQUALS(true, function.counter == 10)function.counter = 0;thread[1] = std::thread(&Function4Wait::consume_with_predicate, std::ref(function), 10);for(int i = 0; i < n; i++){while(function.have_cargo())std::this_thread::yield();function.product(i + 1);}thread[1].join();TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.2 wait_for

struct Function4WaitFor
{volatile int cargo = 0;int counter = 0;std::mutex mutex;std::condition_variable cv;inline bool have_cargo() { return cargo != 0; }inline void consume_cargo() { cargo = 0; }void consume(int n){for(int i = 0; i < n; i++){std::unique_lock<std::mutex> lock(mutex);while(!have_cargo() && cv.wait_for(lock, std::chrono::seconds(1)) == std::cv_status::timeout);std::cerr << "cargo: " << cargo << std::endl;counter++;consume_cargo();}}void consume_with_predicate(int n){for(int i = 0; i < n; i++){std::unique_lock<std::mutex> lock(mutex);while(!cv.wait_for(lock, std::chrono::seconds(1), std::bind(&Function4WaitFor::have_cargo, this)));std::cerr << "cargo: " << cargo << std::endl;counter++;consume_cargo();}}inline void product(int n){std::unique_lock<std::mutex> lock(mutex);cargo = n;cv.notify_one();}
};void ConditionVariableSuite::wait_for()
{Function4WaitFor function;  std::thread thread[2];int n = 10;thread[0] = std::thread(&Function4WaitFor::consume, std::ref(function), 10);for(int i = 0; i < n; i++){while(function.have_cargo())std::this_thread::yield();function.product(i + 1);}thread[0].join();TEST_ASSERT_EQUALS(true, function.counter == 10)function.counter = 0;thread[1] = std::thread(&Function4WaitFor::consume_with_predicate, std::ref(function), 10);for(int i = 0; i < n; i++){while(function.have_cargo())std::this_thread::yield();function.product(i + 1);}thread[1].join();TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.3 wait_until

struct Function4WaitUntil
{volatile int cargo = 0;int counter = 0;std::mutex mutex;std::condition_variable cv;inline bool have_cargo() { return cargo != 0; }inline void consume_cargo() { cargo = 0; }void consume(int n){for(int i = 0; i < n; i++){std::unique_lock<std::mutex> lock(mutex);std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::now() + std::chrono::seconds(1);while(!have_cargo() && cv.wait_until(lock, timePoint) == std::cv_status::timeout);std::cerr << "cargo: " << cargo << std::endl;counter++;consume_cargo();}}void consume_with_predicate(int n){for(int i = 0; i < n; i++){std::unique_lock<std::mutex> lock(mutex);std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::now() + std::chrono::seconds(1);while(!cv.wait_until(lock, timePoint, std::bind(&Function4WaitUntil::have_cargo, this)));std::cerr << "cargo: " << cargo << std::endl;counter++;consume_cargo();}}inline void product(int n){std::unique_lock<std::mutex> lock(mutex);cargo = n;cv.notify_one();}
};void ConditionVariableSuite::wait_until()
{Function4WaitUntil function;  std::thread thread[2];int n = 10;thread[0] = std::thread(&Function4WaitUntil::consume, std::ref(function), 10);for(int i = 0; i < n; i++){while(function.have_cargo())std::this_thread::yield();function.product(i + 1);}thread[0].join();TEST_ASSERT_EQUALS(true, function.counter == 10)function.counter = 0;thread[1] = std::thread(&Function4WaitUntil::consume_with_predicate, std::ref(function), 10);for(int i = 0; i < n; i++){while(function.have_cargo())std::this_thread::yield();function.product(i + 1);}thread[1].join();TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.4 notify_one

struct Function4NotityOne
{int cargo = 0;int counter = 0;std::mutex mutex;std::condition_variable produce;std::condition_variable consume;void consumer(){std::unique_lock<std::mutex> lock(mutex);while(cargo == 0)consume.wait(lock);std::cerr << "cargo: " << cargo << std::endl;cargo = 0;counter++;produce.notify_one();}void producer(int id){std::unique_lock<std::mutex> lock(mutex);while(cargo != 0)produce.wait(lock);cargo = id;consume.notify_one();}
};
void ConditionVariableSuite::notify_one()
{std::thread consumers[10];std::thread producers[10];Function4NotityOne function;for(int i = 0; i < 10; ++i){consumers[i] = std::thread(&Function4NotityOne::consumer, std::ref(function));producers[i] = std::thread(&Function4NotityOne::producer, std::ref(function), i + 1);}for(int i = 0; i < 10; ++i){consumers[i].join();producers[i].join();}TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.5 notiry_all

struct Function4NotiryAll
{bool is_ready = false;std::mutex mutex;std::condition_variable cv;int counter = 0;void print_id(int id){std::unique_lock<std::mutex> lock(mutex);while(!is_ready)cv.wait(lock);std::cerr << "id:" << id << std::endl;counter++;}void go(){std::unique_lock<std::mutex> lock(mutex);is_ready = true;cv.notify_all();}void allgo(){std::unique_lock<std::mutex> lock(mutex);is_ready = true;std::notify_all_at_thread_exit(cv, std::move(lock));}
};void ConditionVariableSuite::notiry_all()
{std::thread threads[10];Function4NotiryAll function;for(int i = 0; i < 10; ++i)threads[i] = std::thread(&Function4NotiryAll::print_id, std::ref(function), i);function.go();for(auto & thread : threads)thread.join();TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.5 notify_all_at_thread_exit

void ConditionVariableSuite::notify_all_at_thread_exit()
{std::thread threads[10];Function4NotiryAll function;for(int i = 0; i < 10; ++i)threads[i] = std::thread(&Function4NotiryAll::print_id, std::ref(function), i);std::thread(&Function4NotiryAll::allgo, std::ref(function)).detach();for(auto & thread : threads)thread.join();TEST_ASSERT_EQUALS(true, function.counter == 10)   
}

说明:

  • notify_all_at_thread_exit 只能在线程中调用,在进程中调用将不起作用。

这篇关于C++并发之条件变量(std::condition_variable)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064310

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

Spring Security 前后端分离场景下的会话并发管理

《SpringSecurity前后端分离场景下的会话并发管理》本文介绍了在前后端分离架构下实现SpringSecurity会话并发管理的问题,传统Web开发中只需简单配置sessionManage... 目录背景分析传统 web 开发中的 sessionManagement 入口ConcurrentSess

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

MySQL中处理数据的并发一致性的实现示例

《MySQL中处理数据的并发一致性的实现示例》在MySQL中处理数据的并发一致性是确保多个用户或应用程序同时访问和修改数据库时,不会导致数据冲突、数据丢失或数据不一致,MySQL通过事务和锁机制来管理... 目录一、事务(Transactions)1. 事务控制语句二、锁(Locks)1. 锁类型2. 锁粒

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c