C++ 线程 一些同步方式

news/2024/9/23 3:16:06/
  • C++ 线程
  • 一些同步方式
    • 1.互斥锁(Mutex)
    • 2. 读写锁(Reader-Writer Lock)
    • 3. 信号量(Semaphore)
    • 4. 原子操作(Atomic)
    • 5. 屏障(Barrier)
    • 6. 条件变量(Condition Variable)

一些同步方式

在多线程编程中,除了条件变量(condition variable)之外,还有其他几种常见的同步机制,每种机制都有其特定的使用场景和优势。以下是一些常见的同步方式:

1.互斥锁(Mutex)

互斥锁是最基本的同步机制,用于保护共享数据,防止多个线程同时访问导致数据竞争。

示例代码:

#include <iostream>
#include <thread>
#include <mutex>// 声明一个互斥锁对象
std::mutex mtx;// 声明一个共享数据变量,初始值为0
int shared_data = 0;// 线程函数:增加共享数据的值
void increment() {// 使用lock_guard锁定互斥锁,确保线程安全std::lock_guard<std::mutex> lock(mtx);// 增加共享数据的值shared_data++;
}int main() {// 创建两个线程,每个线程调用increment函数std::thread t1(increment);std::thread t2(increment);// 等待两个线程完成t1.join();t2.join();// 输出共享数据的最终值std::cout << "Shared data: " << shared_data << std::endl;// 返回0,表示程序正常结束return 0;
}

2. 读写锁(Reader-Writer Lock)

读写锁允许多个读线程同时访问共享数据,但写线程独占访问。适用于读多写少的场景。

示例代码:

#include <iostream>
#include <thread>
#include <shared_mutex>// 声明一个读写锁对象
std::shared_mutex rw_mtx;// 声明一个共享数据变量,初始值为0
int shared_data = 0;// 读线程函数:读取共享数据的值
void read() {// 使用shared_lock锁定读写锁,允许多个读线程同时访问std::shared_lock<std::shared_mutex> lock(rw_mtx);// 输出读取到的共享数据的值std::cout << "Read data: " << shared_data << std::endl;
}// 写线程函数:增加共享数据的值
void write() {// 使用unique_lock锁定读写锁,独占访问,阻止其他读写线程std::unique_lock<std::shared_mutex> lock(rw_mtx);// 增加共享数据的值shared_data++;// 输出写入后的共享数据的值std::cout << "Write data: " << shared_data << std::endl;
}int main() {// 创建一个读线程和一个写线程std::thread t1(read);std::thread t2(write);// 等待两个线程完成t1.join();t2.join();// 返回0,表示程序正常结束return 0;
}

3. 信号量(Semaphore)

信号量用于控制对共享资源的访问,可以用于线程间的同步和互斥。

示例代码:

#include <iostream>
#include <thread>
#include <semaphore>// 声明一个计数信号量对象,初始值为1
std::counting_semaphore<1> sem(1);// 声明一个共享数据变量,初始值为0
int shared_data = 0;// 线程函数:增加共享数据的值
void increment() {// 获取信号量,阻塞直到信号量可用sem.acquire();// 增加共享数据的值shared_data++;// 释放信号量,允许其他线程获取sem.release();
}int main() {// 创建两个线程,每个线程调用increment函数std::thread t1(increment);std::thread t2(increment);// 等待两个线程完成t1.join();t2.join();// 输出共享数据的最终值std::cout << "Shared data: " << shared_data << std::endl;// 返回0,表示程序正常结束return 0;
}

4. 原子操作(Atomic)

原子操作提供了一种无锁的同步机制,适用于对单个变量的简单操作。

示例代码:

#include <iostream>
#include <thread>
#include <atomic>// 声明一个原子整数变量,初始值为0
std::atomic<int> shared_data(0);// 线程函数:增加共享数据的值
void increment() {// 使用原子操作增加共享数据的值shared_data++;
}int main() {// 创建两个线程,每个线程调用increment函数std::thread t1(increment);std::thread t2(increment);// 等待两个线程完成t1.join();t2.join();// 输出共享数据的最终值std::cout << "Shared data: " << shared_data << std::endl;// 返回0,表示程序正常结束return 0;
}

5. 屏障(Barrier)

#include <iostream>
#include <thread>
#include <barrier>// 声明一个屏障对象,初始计数为3
std::barrier bar(3);// 工作线程函数:模拟工作并使用屏障进行同步
void worker() {// 输出工作线程开始的信息std::cout << "Worker started" << std::endl;// 到达屏障并等待,直到所有线程都到达屏障bar.arrive_and_wait();// 输出工作线程结束的信息std::cout << "Worker finished" << std::endl;
}int main() {// 创建三个线程,每个线程调用worker函数std::thread t1(worker);std::thread t2(worker);std::thread t3(worker);// 等待三个线程完成t1.join();t2.join();t3.join();// 返回0,表示程序正常结束return 0;
}

6. 条件变量(Condition Variable)

条件变量用于在一个线程等待某个条件成立时挂起该线程,并在条件成立时通知该线程继续执行。

示例代码:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>// 声明一个互斥锁对象
std::mutex mtx;// 声明一个条件变量对象
std::condition_variable cv;// 声明一个布尔变量,用于表示条件是否成立
bool ready = false;// 工作线程函数:等待条件成立并开始工作
void worker() {// 使用unique_lock锁定互斥锁std::unique_lock<std::mutex> lock(mtx);// 等待条件变量,直到ready为truecv.wait(lock, []{ return ready; });// 输出工作线程开始的信息std::cout << "Worker started" << std::endl;
}// 触发线程函数:设置条件并通知等待的线程
void trigger() {// 使用lock_guard锁定互斥锁std::lock_guard<std::mutex> lock(mtx);// 设置ready为true,表示条件成立ready = true;// 通知一个等待的线程cv.notify_one();
}int main() {// 创建一个工作线程和一个触发线程std::thread t1(worker);std::thread t2(trigger);// 等待两个线程完成t1.join();t2.join();// 返回0,表示程序正常结束return 0;
}

http://www.ppmy.cn/news/1511153.html

相关文章

ES6-ES13学习笔记

目录 初识ES6 变量声明 解构赋值 对象解构 ​编辑 数组解构 ​编辑模版字符串 字符串扩展 includes() repeat() startsWith() endsWith() 数值扩展 二进制和八进制表示法 &#xff08;Number.&#xff09;isFinite()与isNaN() Number.isInteger() Math.trunc …

Spring-MVC 结合 Swagger2

目录 一、引入依赖 二、创建Swagger配置类 三、修改Spring-MVC配置文件 四、在游览器打开 五、配置 Swagger 六、使用 Swagger 七、Swagger 的常用注解 ApiOperation() ApiModel ()、ApiModelProperty () 一、引入依赖 <dependency><groupId>io.springf…

Kotlin之lateinit 和 lazy 区别

目录 lateinitlazy区别总结适用范围&#xff1a;初始化时机&#xff1a;线程安全&#xff1a;检查是否初始化&#xff1a;缓存结果&#xff1a;使用场景 在 Kotlin 中&#xff0c;lateinit 和 lazy 都用于延迟初始化变量&#xff0c;但它们有不同的应用场景和使用方式。 latein…

【机械原理学习】——《机械原理》(第二版)机构部分

机械原理 绪论&#xff1a; 机械机器机构 第一章&#xff1a;平面机构的结构分析 构件与零件 每个独立运动的单元体称为构件机构总是由一些零件组成的‌过盈配合是指两个配合零件之间存在一定的过盈量&#xff0c;即一个零件的孔径比另一个零件的轴径小&#xff0c;装配时…

最常用的正则表达式规则和语法

正则表达式(Regular Expression,简称 regex)是一种用于匹配字符串的强大工具。它使用特定的语法规则来定义字符串模式,可以用来搜索、替换、验证字符串等。以下是一些常用的正则表达式规则和语法: 1. 基本字符匹配 . :匹配任意单个字符(除了换行符)。 示例:a.c 可以匹…

SQL每日一练-0814

今日SQL题难度&#xff1a;&#x1f31f;☆☆☆☆☆☆☆☆☆ 1、题目要求 找出每个部门中薪资最高的员工显示部门ID、部门名称、员工ID、员工姓名以及对应的薪资 2、表和虚拟数据 现有两个表&#xff1a;Employees 和 Departments&#xff0c;记录了员工和部门信息。…

谷歌的高级指令有哪些

今天会分享一些组合用法&#xff0c;这样就能节省许多时间可以放在跟进客户上面&#xff08;本文只介绍谷歌的搜索指令&#xff0c;并无推广&#xff09; part one 谷歌常用的搜索引擎指令&#xff1a; 1、Inurl&#xff0c;在网址中 2、Intext&#xff0c;在网页内容中 3、…

Spring boot + mybatis plus 多数据源

有参照链接&#xff1a;SpringBoot配置多数据源的一款框架(dynamic-datasource-spring-boot-starter) - 编程宝库 场景&#xff1a;A公司为总公司&#xff0c;B公司为分公司&#xff0c;B公司上传的数据需要保存到A公司中。 application.yml的配置 spring:datasource:dynami…