技术标签: C/C++ c++ linux多线程 线程同步 多线程编程 开发语言
互斥和同步的区别:互斥是对共同资源的互斥访问,访问是乱序的,同步就是协调步调,按照一定顺序执行。同步一般已经实现了互斥,通过条件设置实现顺序访问。
C语言线程互斥和同步方式,在文章 C语言多线程同步方式一,C语言多线程同步方式二中已经做了介绍且有实例。
C语言线程同步的常见方式:
1. 互斥锁
2. 条件变量
3. 读写锁
4. 自旋锁
5. 信号量
6. 关卡
以下着重介绍几种常用的C++线程同步方式,包括互斥锁、条件变量、信号量
c++中互斥锁的使用比c复杂一些。c++可使用的互斥锁相关的类有
1. std::mutex
2. std::lock
3. std::lock_guard
4. std::unique_lock
5. std::scoped_lock
#include <thread>
#include <mutex>
#include <string>
#include <iostream>
std::mutex myMutex;
int num = 0;
void PrintNum(std::string str)
{
while (num < 10)
{
myMutex.lock(); // 加锁
std::cout << str << " num = " << num << std::endl;
num++;
myMutex.unlock(); // 解锁
}
}
int main()
{
std::thread threadOne(PrintNum, "thread one");
std::thread threadTwo(PrintNum, "thread two");
threadOne.join();
threadTwo.join();
return 0;
}
// 编译运行
g++ -o main main.cpp -pthread
这种需要手动解锁的都有忘记解锁的风险
int num = 0;
std::mutex mutex1;
std::mutex mutex2;
void safe_increment()
{
/*同时锁两个*/
std::lock(mutex1, mutex2);
for (int i = 0; i < 10000000; i++)
{
++num;
}
/*需要手动解锁*/
std::cout << std::this_thread::get_id() << ": " << num << '\n';
mutex1.unlock();
mutex2.unlock();
}
std::mutex mutex1;
std::mutex mutex2;
std::lock(mutex1, mutex2); // 参数为互斥量,同时锁定两个互斥量
std::lock_guard lock1(mutex1, std::adopt_lock);
std::lock_guard lock2(mutex2, std::adopt_lock);
lock_guard使用adopt_lock参数表示这个互斥量已经被锁定了,不需要在构造函数中再加锁了
std::mutex mutex1;
std::mutex mutex2;
std::unique_lock lock1(mutex1, std::defer_lock);
std::unique_lock lock2(mutex2, std::defer_lock);
std::lock(lock1, lock2); // 参数为对象,同时锁定lock1和lock2两个对象
// 如果不需要两个同时锁定,也可以各自锁定
lock1.lock();
lock2.lock();
unique_lock中使用了defer_lock参数,表示加锁的动作可以留到后面进行,可能是加锁之前还有一些操作
std::mutex mutex1;
std::mutex mutex2;
void Function()
{
while (true) {
int result = std::try_lock(mutex1, mutex2);
if (result == -1) {
// do something
mutex1.unlock();
mutex2.unlock();
}
}
}
while (ros::ok()) {
{
std::mutex mutexVar,
std::lock_guard<std::mutex> lockGuard(mutexVar);
// do something
} // 离开作用域自动解锁
...
}
while (ros::ok()) {
{
std::mutex mutexVar,
std::unique_lock<std::mutex> uniqueLock(mutexVar);
if (!condition) {
uniqueLock.unlock(); // 手动解锁
continue;
}
// do something
} // 离开作用域自动解锁
...
}
list<int> myList; // 受保护对象
mutex myMutex;
void Function()
{
for (int num = 0; num < 10000; num++) {
std::unique_lock<std::mutex> my_unique(myMutex, std::try_to_lock);
if(my_unique.owns_lock()){
cout<<"插入数据: "<<num<<endl;
myList.push_back(num);
}
else{
cout<<"没能拿到锁,只能干点别的事"<<endl;
}
}
}
std::mutex mutex1;
std::mutex mutex2;
std::scoped_lock scopedLock(mutex1, mutex2);
// 相当于
std::lock(mutex1, mutex2); // 参数为互斥量,同时锁定两个互斥量
std::lock_guard lock1(mutex1, std::adopt_lock);
std::lock_guard lock2(mutex2, std::adopt_lock);
// 或者相当于
std::unique_lock lock1(mutex1, std::defer_lock);
std::unique_lock lock2(mutex2, std::defer_lock);
std::lock(lock1, lock2); // 参数为对象,同时锁定lock1和lock2两个对象
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
using namespace std;
std::mutex myMutex; // mutual exclusive lock
std::condition_variable condVar; // condition variable
std::vector<int> vec; // protected object
void Consumer()
{
std::unique_lock<std::mutex> lock(myMutex);
while (vec.empty()) {
condVar.wait(lock);
}
std::cout << "consumer " << vec.size() << "\n";
}
void Producer()
{
std::unique_lock<std::mutex> lock(myMutex);
vec.push_back(1);
condVar.notify_one(); // or condVar.notify_all()
std::cout << "producer \n";
}
int main()
{
std::thread newThread(Consumer);
//newThread.detach(); // main-thread or sub-thread split
Producer();
newThread.join();
return 0;
}
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
class Semaphore
{
public:
Semaphore(int value = 1) : count(value) {
}
virtual ~Semaphore() = default;
// P操作
void P()
{
unique_lock<mutex> lock(myMutex);
--count;
if (count < 0) //资源已经不足挂起等通知
condVar.wait(lock);
}
// V操作
void V()
{
unique_lock<mutex> lock(myMutex);
++count;
if (count <= 0) // 有资源了,有线程挂起的话,通知一下
condVar.notify_one();
}
private:
int count;
mutex myMutex;
condition_variable condVar;
};
// 初始化
Semaphore plate(1), apple(0), orange(0);
void Father()
{
while (true)
{
plate.P();
cout << "往盘中放一个苹果" << endl;
apple.V();
}
}
void Mother()
{
while (true)
{
plate.P();
cout << "往盘中放一个橘子" << endl;
orange.V();
}
}
void Son()
{
while (true)
{
apple.P();
cout << "儿子吃苹果" << endl;
plate.V();
}
}
void Daughter()
{
while (true)
{
orange.P();
cout << "女儿吃橘子" << endl;
plate.V();
}
}
int main()
{
std::thread farther(Father), mother(Mother), son(Son), daughter(Daughter);
farther.join();
mother.join();
son.join();
daughter.join();
return 0;
}
以下内容待补充总结。
shared_lock用法:shared_lock用法
lock_guard和scoped_lock的区别:lock_guard和scoped_lock区别
binary_semaphore的用法:binary_semaphore的用法
参考文章:
互斥锁的用法
std::lock的使用
std::scoped的使用
条件变量的使用
信号量的使用
c++信号量使用
c++线程同步方法
created by shuaixio, 2022.04.30
文章浏览阅读1.2k次。数学题_计算几何 cfgym
文章浏览阅读1k次。问题描述:springaop无法拦截service方法中调用,在service类中方法A调用带有切面注解的方法B,切面失效问题分析:AOP底层实现: 拦截器的实现原理就是动态代理,实现AOP机制。Spring 的代理实现有两种:一是基于 JDK Dynamic Proxy 技术而实现的;二是基于 CGLIB 技术而实现的。如果目标对象实现了接口,在默认情况下Spring会采用JDK的动态代理实现AOP; ***总之是类(接口类)级别的代理***;解决思路: 只要将方法A调用方法B过程中添加_aop 不能拦截service
文章浏览阅读645次。Java批量生成二维码实例_java批量生成二维码
文章浏览阅读961次。yum -y localinstall mysql80-community-release-el7-1.noarch.rpmpip3.6 install mycli_centos8 安装vastbase数据库
文章浏览阅读2.2k次。普通属性子类可以继承父类的属性值,后续操作互不影响。静态属性:public class Main7 extends Father{ //static int test = 11; public static void main(String[] args) { test++; Father father = new Father(); System.out.printl..._一个子类继承另一个父类然后子类new对象属性分装不进去
文章浏览阅读2.4k次,点赞4次,收藏14次。参考转自:https://blog.csdn.net/yanglusheng/article/details/52268234https://blog.csdn.net/sunboyiris/article/details/780826991、 相机参数是三种不同的参数。相机的内参数是六个分别为:1/dx、1/dy、r、u0、v0、f。opencv1里的说内参数是4个其为fx、..._摄像机四个内参
文章浏览阅读1.6k次,点赞6次,收藏12次。Linux下MySQL的安装与使用一、安装前说明1、Linux系统及工具的准备安装并启动好两台虚拟机: CentOS 7掌握克隆虚拟机的操作mac地址主机名ip地址UUID安装有 Xshell 和 Xftp 等访问CentOS系统的工具CentOS6和CentOS7在MySQL的使用中的区别防火墙:6是iptables,7是firewalld启动服务的命令:6是service,7是systemctl2、查看是否安装过MySQL如果你是用rpm安装, 检
文章浏览阅读1k次。先暂时记录一下首先 Chrom浏览器一定要匹配好, 不能在百度搜索中下载最新的谷歌浏览器,我现在下的是版本50的浏览器。匹配的chromedriver.exe 是2.9的。32位的同样也使用64位的。 需要把chromedriver.exe 安装在谷歌浏览器的安装目录下,路径是:C:\Program Files (x86)\Google\Chrome\Application与chrome.ex_京东爬虫 对浏览器的要求
文章浏览阅读890次。网页的线框图是非常直观、但是也没什么技术上难点的东西。只需要你大概描出页面上需要的一些元素,比如头部、导航、页脚等等,最多再就是一些交互、内容区域什么的。但这对于任何网络应用的开发都是非常重要的。当然有很多种方法可以做这件事情,最简单的就是拿起纸和笔,但是在这篇文章中,我们要介绍的是一些非常高效好用的在线原型工具,并且他们完全免费。Lumzy 快速原型工具使用Lumzy你可以为你的应用创建_将网站直接转换成原型图
文章浏览阅读1k次。深度学习中的样本不均衡问题_深度学习重采样
文章浏览阅读2.5k次。1.多标签即一条语句可能有多个类别划分。例如,这个酸菜鱼又酸又辣。属于酸和辣两个标签。在采用神经网络学习时,最后一层的激活函数应采用sigmoid激活函数,相当于对这条语句做了多个二分类。2.多分类即每条语句只有一个标签,在采用神经网络学习时,最后一层的激活函数应采用softmax激活函数,最后选取类别中的最大值作为预测结果。关于sigmoid和softmax 的区别此处再说明。本次数据集的格式为:关于LSTM的学习可以参考这篇。关于词向量化的方式,本文采用keras 内置Tokenizer A_keras lstm多分类
文章浏览阅读2.5w次,点赞3次,收藏38次。常用的抓包工具有: tcpdump (linux) wireshark (windows) tcpflow (linux) httpwatch (windows) 浏览器自带抓包工具 (windows)tcpdump (linux)tcpdump是linux下的抓包工具,一般使用比较习惯于,在linux下用tcpdump抓包,结果存入文件,把文件导入windows下用window..._包分析工具