当前位置: 首页 > news >正文

C++ Linux多线程同步通信-信号量

原文链接:C++ Linux多线程同步通信-信号量

介绍

C++多线程能够提升程序的资源利用率,提升效率.涉及到的库有:
thread,
mutex,
chrono,
semaphore

线程库thread

构造函数:线程构造的参数需要使用ref和cref包装后保证深拷贝
std::thread t() 空线程对象
std::thread t(func,args) 线程函数对象
std::thread t(thread u) 移动线程对象
std::thread t=u  赋值形式的移动线程对象
成员函数:
bool joinable() 是否可加入 
.join() 加入
几种构造形式
  1. 空线程
  2. 函数线程
  3. 类函数线程
  4. 移动复制线程
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;int func1(int n){cout<<"func1 thread run\n";for(int i=0;i<n;i++){cout<<"func1 thread:"<<i<<"\n";this_thread::sleep_for(std::chrono::milliseconds(10));}return 0;
}class M{
public:M(){}int func2(int n){cout<<"M.func2 thread run\n";for(int i=0;i<n;i++){cout<<"M.func2 thread:"<<i<<"\n";this_thread::sleep_for(std::chrono::milliseconds(10));}return 0;}
};int main()
{ thread t1; //空线程thread t1_(func1,4); //函数参数线程M m;thread t2(&M::func2,&m,3); //带参数类线程cout<<"t1 is:"<<t1.joinable()<<"  t1_ is:"<<t1_.joinable()<<"\n";t1=move(t1_); //移动线程//或者thread t2(move(t1_));cout<<"t1 is:"<<t1.joinable()<<"  t1_ is:"<<t1_.joinable()<<"\n";if(t1.joinable()) t1.join();if(t1_.joinable()) t1_.join();if(t2.joinable()) t2.join();return 0;
}
线程传参

对于一般数据可以直接传入,但是引用数据需要深拷贝传参.

当主线程引用数据改变时,其他线程使用ref深拷贝的同步改变.但是其他线程改变数据不影响主线程的对象(?)

#include <iostream>
#include <thread>
#include <vector>
using namespace std;int func1(int n, vector<int> a) {cout << "other thread arr[n-1]=" << a[n-1] << "\n";a[0]=n-1;return 0;
}int main() { int n = 10;vector<int> a(n);for (int i = 0; i < n; i++) a[i] = i;vector<int> b(n);for (int i = 0; i < n; i++) b[i] = i;thread t1(func1, n, ref(a)); // 传递引用thread t2(func1, n, b);      // 传递副本a[n-1]=0;b[n-1]=0;    // 等待线程完成if (t1.joinable()) t1.join();if (t2.joinable()) t2.join();cout << "main thread a[0]=" << a[0] << "\n";cout << "main thread b[0]=" << b[0] << "\n";return 0;
}other thread arr[n-1]=9
other thread arr[n-1]=0
main thread a[0]=0
main thread b[0]=0

线程同步与通信

同步

互斥锁

互斥锁能够实现简单的互斥操作,保证临界区互斥访问,实现方式有3种:

  1. mutex手动加锁: 手动加锁和解锁不可靠,当程序异常或忘记加锁时可能死锁

  2. lock_guard自动锁: 变量的生命周期就是临界区范围,可以通过手动{}实现

  3. unique_lock: 能够实现同时上多个锁,使用defer_lock手动上锁


#include <iostream>
#include<thread>
#include<mutex>
#include<chrono>using namespace std;
int c=0;mutex m;
// 1. 
void func1() {for(int i=0; i<3; i++) {m.lock();c++;m.unlock();cout<<c<<"\t";}
}// 2.
void func2() {for(int i=0; i<3; i++) {{lock_guard<mutex> guard(m);c++;}cout<<c<<"\t";}
}
// 3.
mutex n1;
mutex n2;
void func3() {for(int i=0; i<3; i++) {{unique_lock<mutex> um(m,defer_lock);unique_lock<mutex> un1(n1,defer_lock);unique_lock<mutex> un2(n2,defer_lock);//before lock ..lock(um,un1,un2); //同时上锁 c++;}cout<<c<<"\t";}
}int main()
{thread t1(func3),t2(func3);if(t1.joinable()) t1.join();if(t2.joinable()) t2.join();return 0;
}
信号量

提供 counting_semaphore和二维信号量,但是二维的可用用mutex.
counting_semaphore没有直接提供获取当前信号量值的函数,可以使用POSIX实现或者对counting实现一个封装

直接counting_semaphore实现的生产者消费者


#include <iostream>
#include<thread>
#include<chrono>
#include <semaphore>using namespace std;
counting_semaphore Empty(3),Use(0);
int v=0;
void producer() {int i=0;while(i++<10){Empty.acquire();cout<<"create 1\n";Use.release(1);}
}
void consumer() {int i=0;while(i++<10){Use.acquire();cout<<"use 1\n";Empty.release(1);}
}
int main()
{thread t1(producer),t2(consumer);if(t1.joinable()) t1.join();if(t2.joinable()) t2.join();return 0;
}

实现可计数的信号量,该信号量可以实现进程同步

#include <iostream>
#include<thread>
#include<chrono>
#include <semaphore>using namespace std;
sem_t Empty,Use;
int v=0;
void producer() {int i=0;while(i++<10){sem_wait(&Empty);sem_getvalue(&Empty,&v);cout<<"create 1 contain("<<v<<")\n";this_thread::sleep_for(chrono::milliseconds(10));sem_post(&Use);}
}
void consumer() {int i=0;while(i++<10){sem_wait(&Use);sem_getvalue(&Empty,&v);cout<<"use 1 contain("<<v<<")\n";this_thread::sleep_for(chrono::milliseconds(1));sem_post(&Empty);}
}
int main()
{sem_init(&Empty, 0, 3);sem_init(&Use, 0, 0);thread t1(producer),t2(consumer),t3(consumer);if(t1.joinable()) t1.join();if(t2.joinable()) t2.join();if(t3.joinable()) t3.join();return 0;
}

通信

线程的通信通过全局的共享变量搭配信号量即可完成.需要专门的通信主要是对于进程而言

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux系统应用之知识补充——OpenEuler(欧拉)的安装和基础配置
  • linux-centos 设置系统时间
  • python selenium网页操作
  • GlusterFS分布式存储
  • 【OJ刷题】双指针问题6
  • pWnOS的第二种全新解法(ssh私钥破解、webmin漏洞提权)
  • C++3D迷宫
  • opencv之图像梯度
  • # wps必须要登录激活才能使用吗?
  • Java多线程2
  • 开发板与ubuntu建立网络通信(NFS和TFTP协议搭建)
  • 【GESP】C++一级练习BCQM3006,多行输出
  • MySQL——数据库的高级操作(三)权限管理(4)收回权限
  • JUC学习笔记(一)
  • android 老项目中用到的jar包不存在,通过离线的方法加载
  • canvas绘制圆角头像
  • FineReport中如何实现自动滚屏效果
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • IP路由与转发
  • java8 Stream Pipelines 浅析
  • js学习笔记
  • Mysql5.6主从复制
  • Vue ES6 Jade Scss Webpack Gulp
  • 从0实现一个tiny react(三)生命周期
  • 从PHP迁移至Golang - 基础篇
  • 近期前端发展计划
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 王永庆:技术创新改变教育未来
  • 线上 python http server profile 实践
  • 项目管理碎碎念系列之一:干系人管理
  • 一天一个设计模式之JS实现——适配器模式
  • 优化 Vue 项目编译文件大小
  • 原生Ajax
  • 再次简单明了总结flex布局,一看就懂...
  • 正则表达式小结
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​第20课 在Android Native开发中加入新的C++类
  • # Redis 入门到精通(九)-- 主从复制(1)
  • #include
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #pragma multi_compile #pragma shader_feature
  • $LayoutParams cannot be cast to android.widget.RelativeLayout$LayoutParams
  • (2)nginx 安装、启停
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (C语言)球球大作战
  • (Git) gitignore基础使用
  • (Python) SOAP Web Service (HTTP POST)
  • (二)c52学习之旅-简单了解单片机
  • (学习总结16)C++模版2
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • ****三次握手和四次挥手
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查