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

【Linux】多线程编程 - 同步/条件变量/信号量

目录

一.线程同步

1.什么是线程同步

2.为什么需要线程同步

3.如何实现线程同步

二.条件变量

1.常见接口以及使用

2.wiat/signal中的第二个参数mutex的意义

3.代码验证

三.POSIX信号量

1.概念

2.常见接口以及使用

四.条件变量vsPOSIX信号量


一.线程同步

1.什么是线程同步

同步: 在保证数据安全的情况下, 让线程能按照某种特定顺序访问临界资源, 从而有效避免饥饿问题, 主要为了解决访问临界资源合理性问题

其中, 按照某种特定顺序访问临界资源, 实际上操作系统的调度队列自动帮助我们维护的, 对于我们而言是透明的, 因为如果有线程在等待资源, 那么一定是一个个的被挂起, 自然就有了顺序性

2.为什么需要线程同步

情景一: 假设有某个线程竞争能力比较强, 就会导致其他线程迟迟访问不到临界资源, 造成饥饿问题

情景二: 线程在使用临界资源前必须要检测临界资源是否就绪, 检测这一过程本质上也是访问临界资源, 那么就需要互斥的访问(加锁解锁), 如果临界资源没有准备就绪, 线程就会不断地检测, 即不断地互斥访问, 也就是在不断加锁解锁, 频繁做无效的加锁解锁工作, 是一种极大的资源浪费

情景三: 生活中的例子, 当我们要去商店买东西时, 总是要问一下是否还有货, 如果没有就要改天再来, 那么我们不可能每次问的时候都在亲自跑到商店去问, 而是在第一次问的时候就留好了联系方式, 如果有货的话老板会联系我来拿, 这本质上就是资源已就绪, 老板唤醒了我这个等待中的线程, 让我来访问

3.如何实现线程同步

线程同步的本质上就是: 对临界资源做检查, 如果资源不就绪就等待, 资源一但就绪就将等待中的线程唤醒, 从而高效有序的进行访问, 避免不必要的锁资源浪费以及饥饿问题

对临界资源检查, 本质也是在访问临界资源, 所以也要互斥进行(信号量不需要, 后续会解释)

如果通过编码的方式实现线程同步:

1.条件变量

2.POSIX信号量

二.条件变量

本质上条件变量就是一个"等待-唤醒"的过程

1.常见接口以及使用

需要包头文件<pthread.h>

类型:

pthread_cond_t

定义方式:

与pthread_mutex_t的定义方式一样 (互斥量mutex详解, 传送入口: http://t.csdn.cn/ikHAk)

定义为全局 or 定义为静态: pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

定义为局部:

       int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

       int pthread_cond_destroy(pthread_cond_t *cond);

使用方式:

等待

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

唤醒

int pthread_cond_broadcast(pthread_cond_t *cond); (广播, 唤醒全部正在等待线程)
int pthread_cond_signal(pthread_cond_t *cond); (只唤醒一个)

2.wiat/signal中的第二个参数mutex的意义

对临界资源检查, 本质也是在访问临界资源, 所以也要互斥进行

在使用上, 一定是

pthread_mutex_lock(&mutex);

pthread_cond_wait(&cond, &mutex);

pthread_mutex_unlock(&mutex);

-------------------------------------------------

唤醒pthread_cond_signal(&cond);是否互斥进行看具体场景

在wait接口传入锁地址的意义:

如果一个持有锁的线程挂起等待了, 它是持有锁等待的, 会导致其他线程申请不到锁

所以pthread_cond_wait接口的内部实现, 是先解锁, 等到被唤醒的时候再加锁, 这样的一个设计

所以就需要传入mutex地址

3.代码验证

#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>const static size_t THREAD_NUM = 3;typedef void (*func_t)(const std::string &, pthread_mutex_t *, pthread_cond_t *);volatile bool quit = false;struct ThreadData
{ThreadData(const std::string &name, func_t func, pthread_mutex_t *mutex, pthread_cond_t *cond): _name(name), _func(func), _mutex(mutex), _cond(cond){}std::string _name;func_t _func;pthread_mutex_t *_mutex;pthread_cond_t *_cond;
};void func1(const std::string &info, pthread_mutex_t *mutex, pthread_cond_t *cond)
{while (!quit){pthread_mutex_lock(mutex);pthread_cond_wait(cond, mutex);if (!quit)std::cout << info << " -> "<< "func1" << std::endl;pthread_mutex_unlock(mutex);// sleep(1);}
}void func2(const std::string &info, pthread_mutex_t *mutex, pthread_cond_t *cond)
{while (!quit){pthread_mutex_lock(mutex);pthread_cond_wait(cond, mutex);if (!quit)std::cout << info << " -> "<< "func2" << std::endl;pthread_mutex_unlock(mutex);// sleep(1);}
}void func3(const std::string &info, pthread_mutex_t *mutex, pthread_cond_t *cond)
{while (!quit){pthread_mutex_lock(mutex);pthread_cond_wait(cond, mutex);if (!quit)std::cout << info << " -> "<< "func3" << std::endl;pthread_mutex_unlock(mutex);// sleep(1);}
}void *entry(void *args)
{ThreadData *td = (ThreadData *)args;td->_func(td->_name, td->_mutex, td->_cond);delete td;return nullptr;
}int main()
{pthread_t t[THREAD_NUM];func_t funcArr[THREAD_NUM] = {func1, func2, func3};pthread_mutex_t mutex;pthread_cond_t cond;pthread_mutex_init(&mutex, nullptr);pthread_cond_init(&cond, nullptr);// 创建线程// 让这些线程分别执行自己的函数for (size_t i = 0; i < THREAD_NUM; ++i){std::string str = "thread ";str += std::to_string(i + 1);ThreadData *td = new ThreadData(str, funcArr[i], &mutex, &cond);pthread_create(t + i, nullptr, entry, (void *)td);}std::cout << "3秒后, 随机单独唤醒10次, 每次一秒" << std::endl;sleep(3);size_t count = 10;for (size_t i = 0; i < count; ++i){std::cout << "正在唤醒中..." << std::endl;// pthread_cond_signal(&cond);pthread_cond_broadcast(&cond);sleep(1);}std::cout << "测试结束" << std::endl;quit = true;// 最后广播一次, 将所有线程再唤醒一次判断结束pthread_cond_broadcast(&cond);// 回收线程for (size_t i = 0; i < THREAD_NUM; ++i){pthread_join(t[i], nullptr);std::cout << "线程: " << i + 1 << "已被回收" << std::endl;}pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

三.POSIX信号量

1.概念

POSIX信号量和System V信号量作用相同, 都是用于同步的访问共享资源的; 不同的是, POSIX可以用于线程同步

POSIX信号量的本质: 就是一个具有原子性的计数器, 其原子性由库给我们提供好了

对应的两套操作:

P操作 - 本质上是申请, 计数器--

V操作 - 本质上是释放, 计数器++

本质上POSIX信号量更像是一种对资源的预定机制

2.常见接口以及使用

需要包头文件<semaphore.h>

类型:

sem_t

定义方式:

int sem_init(sem_t* sem, int pshared, unsigned int value);

int sem_destory(sem_t* sem);

参数解释:

        pshared: 0表示线程间共享, 非0表示进程间共享

        value: 信号量初始值

使用方式:

P操作

int sem_wait(sem_t* sem);

V操作

int sem_post(sem_t* sem);

四.条件变量vsPOSIX信号量

实现线程同步可以有很多种方式

其中1.条件变量 2.POSIX信号量

那么什么时候用条件变量?什么时候用POSIX信号量呢?

实际上, 条件变量更倾向于不知道临界资源具体有多少, 如果临界资源不够了, 通过统一"等待"的方式来等待临界资源就绪; 而POSIX信号量, 是一种对临界资源的预定机制, 需要明确知道还有多少临界资源可供分配, 才能对计数器做具体的"-- or ++"操作, 即PV操作

相关文章:

【Linux】多线程编程 - 同步/条件变量/信号量

目录 一.线程同步 1.什么是线程同步 2.为什么需要线程同步 3.如何实现线程同步 二.条件变量 1.常见接口以及使用 2.wiat/signal中的第二个参数mutex的意义 3.代码验证 三.POSIX信号量 1.概念 2.常见接口以及使用 四.条件变量vsPOSIX信号量 一.线程同步 1.什么是线…...

ES优化方案

ES优化&联合HBASE&#xff1a; 【Elasticsearch】优秀实践-ESHbase的实现_少加点香菜的博客-CSDN博客_sceshbase ES写入性能优化方案 ElasticSearch 调优笔记_index.refresh_interval_六月飞雪的博客-CSDN博客 es如何提升写入性能_婲落ヽ紅顏誶的博客-CSDN博客_es写入性…...

从数据备份保护到完整生命周期管理平台,爱数全新发布 AnyBackup Family 8

编辑 | 宋慧 出品 | CSDN 云计算 从2003年创业&#xff0c;开始做数据备份技术&#xff0c;爱数已经走过了近20年的时间。现在&#xff0c;数据的价值被越来越多的业界与用户看到&#xff0c;数据分析应用赛道近年一直持续火热。而现在的爱数在做的&#xff0c;已经从数据的备…...

Go 微服务开发框架 DMicro 的设计思路

Go 微服务开发框架 DMicro 的设计思路 DMicro 源码地址: Gitee:dmicro: dmicro是一个高效、可扩展且简单易用的微服务框架。包含drpc,dserver等 背景 DMicro 诞生的背景&#xff0c;是因为我写了 10 来年的 PHP&#xff0c;想在公司内部推广 Go, 公司内部的组件及 rpc 协议都…...

浅谈功能测试

1.功能测试流程 1.1 功能测试流程 # 功能测试大致按照以下流程进行: (1).需求分析与评审(2).测试计划与测试方案(3).测试用例设计(4).测试用例评审(5).执行用例(6).缺陷跟踪及报告产出 1.2 功能测试流程详解 (1).需求分析与评审 功能测试应从需求出发, 功能测试就是尽量覆…...

UDP的详细解析

UDP的详细解析 文章目录UDP的详细解析UDP 概述UDP的首部格式检验和的计算抓包测试参考TCP/IP运输层的两个主要协议都是互联网的正式标准&#xff0c;即&#xff1a;用户数据报协议UDP (User Datagram Protocol)传输控制协议TCP (Transmission Control Protocol) 按照OSI的术语…...

史上最详细JUC教程之Synchronized与锁升级详解

在Java早期版本中&#xff0c;synchronized属于重量级锁&#xff0c;效率低下&#xff0c;因为监视器锁&#xff08;monitor&#xff09;是依赖于底层的操作系统的Mutex Lock来实现的&#xff0c;挂起线程和恢复线程都需要转入内核态去完成&#xff0c;阻塞或唤醒一个Java线程需…...

Vue|初识Vue

Vue是一款用于构建用户界面的JavaScript框架。它基于标准HTML、CSS和JavaScript构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助开发者高效地开发用户界面。 初识Vue1. Vue简介2. 开发准备3. 模板语法3.1 差值语法3.2 指令语法4. 数据绑定4.1 单向数据…...

在职阿里6年,一个29岁女软件测试工程师的心声

简单的先说一下&#xff0c;坐标杭州&#xff0c;14届本科毕业&#xff0c;算上年前在阿里巴巴的面试&#xff0c;一共有面试了有6家公司&#xff08;因为不想请假&#xff0c;因此只是每个晚上去其他公司面试&#xff0c;所以面试的公司比较少&#xff09;其中成功的有4家&…...

(C语言)自定义类型,枚举与联合

问&#xff1a;1. 结构体在自引用的时候不能怎么样&#xff1f;可以怎么样&#xff1f;2. Solve the problems&#xff1a;自定义一个学生结构体类型&#xff0c;要包含姓名&#xff0c;性别&#xff0c;年龄&#xff0c;六科成绩&#xff0c;家乡&#xff08;也为结构体&#…...

node.js服务端笔记文档学会写接口,学习分类:path、包、模块化、fs、express、中间件、jwt、开发模式、cors。

node.js 学习笔记 node.js服务端笔记文档学会写接口&#xff0c;path、包、模块化、fs、express、中间件、JWT、开发模式、cors。 gitee&#xff1a;代码接口笔记 1什么是node.js nodejs 是基于ChromeV8&#xff0c;引擎的一个javaScript 运行环境。node.js 无法使用DOM和BO…...

初始C++(三):引用

文章目录一.引用的概念二.引用的使用1.引用作为输出型参数2. 引用作为函数返回值3.const引用三.引用的一些小问题四.引用和指针五.引用和指针的区别一.引用的概念 引用的作用是给一个已经存在的变量取别名&#xff0c;编译器不会为引用变量开空间&#xff0c;引用变量和被他引…...

【前端】参考C站动态发红包界面,高度还原布局和交互

最近有些小伙伴咨询博主说前端布局好难&#xff0c;其实都是熟能生巧&#xff01; 模仿C站动态发红包界面&#xff0c;cssdiv实现布局&#xff0c;纯javascript实现交互效果 目录 1、界面效果 2、界面分析 2.1、整体结构 2.2、标题 2.3、表单 2.4、按钮 3、代码实现 3.…...

VR全景带你浪漫“狂飙”情人节,见证甜蜜心动

当情人节遇上VR&#xff0c;足以让情侣过一个难忘的情人节。马上情人节就要到了&#xff0c;大家是不是还在绞尽脑汁的想着&#xff0c;如何和另一半过一个浪漫的情人节呢&#xff1f;老套的剧情已经不能吸引人了&#xff0c;让我们看看VR全景给情人节带来了哪些不同的体验吧&a…...

Linux系统安全之iptables防火墙

目录 一.iptables防火墙基本介绍 二.iptables的四表五链 三.iptables的配置 1.iptables的安装 2.iptables防火墙的配置方法 四.添加、查看、删除规则 1.查看(fliter)表中的所有链 iptables -L 2.使用数字形式(fliter)表所有链 查看输出结果 iptables -nL 3.清空表中所…...

【C#基础】C# 变量与常量的使用

序号系列文章1【C#基础】C# 程序通用结构2【C#基础】C# 基础语法解析3【C#基础】C# 数据类型总结文章目录前言一. 变量&#xff08;variable&#xff09;1&#xff0c;变量定义及初始化2&#xff0c;变量的类别3&#xff0c;接收输出变量二. 常量&#xff08;constant&#xff…...

[ 常用工具篇 ] CobaltStrike(CS神器)基础(一) -- 安装及设置监听器详解

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

Redis集群

Redis集群 本章是基于CentOS7下的Redis集群教程&#xff0c;包括&#xff1a; 单机安装RedisRedis主从Redis分片集群 1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录&#xff…...

00---C++入门

1. C关键字(C98) C总计63个关键字&#xff0c;C语言32个关键字 2. 命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进…...

Spring-事务2

文章目录前言一、事务的特性&#xff08;ACID&#xff09;二、事务的隔离级别三、spring中的事务平台事务管理器.事务定义ISOLation_XXX&#xff1a;**事务隔离级别.**PROPAGATION_XXX&#xff1a;**事务的传播行为**.事务状态关系&#xff1a;四、使用XML文件配置事务1、 搭建…...

Windows Git Bash 配置

Windows Git Bash 配置 本文参考的文章&#xff1a; 在 Windows 的 Git Bash 中使用包管理器 - iris (ginshio.org)Git bash 安装 pacman & Windows 解压 zst 文件 | 伪斜杠青年 (lckiss.com) 一、Git的安装 Git 的安装应该是都会的&#xff0c;但还是应该说以下&#…...

java代码整合kettle9.3实现读取表中的数据,生成excel文件

java代码整合kettle9.3实现读取表中的数据&#xff0c;生成excel文件 1.简介 本次使用java代码整合kettle9.3版本&#xff0c;数据库使用mysql。 2.jar包导入 项目需要依赖部分kettle中的jar包&#xff0c;请将这部分jar包自行导入maven仓库。 <dependency><groupId…...

分享微信点餐小程序搭建步骤_微信点餐功能怎么做

线下餐饮实体店都开始摸索发展网上订餐服务。最多人选择的是入驻外卖平台&#xff0c;但抽成高&#xff0c;推广还要另买流量等问题&#xff0c;也让不少商家入不敷出。在这种情况下&#xff0c;建立自己的微信订餐小程序&#xff0c;做自己的私域流量是另一种捷径。那么&#…...

4、数组、切片、map、channel

目录一、数组二、切片三、map四、channel五、引用类型一、数组 数组&#xff1a; 数组是块连续的内存空间&#xff0c;在声明的时候必须指定长度&#xff0c;且长度不能改变所以数组在声明的时候就可以把内存空间分配好&#xff0c;并赋上默认值&#xff0c;即完成了初始化数组…...

270 uuid

270 uuid 用途 For the creation of RFC4122 UUIDs 可靠性 10000 星星 适应于浏览器或者服务器 官网链接 https://www.npmjs.com/package/uuid https://github.com/uuidjs/uuid 基本使用 import { v4 as uuidv4 } from uuid; uuidv4(); // ⇨ 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3d…...

2023最新简历模板免费下载

下面分享5个简历模板网站&#xff0c;免费下载&#xff0c;建议收藏&#xff01; 2023用最漂亮的简历模板&#xff0c;让面试官眼前一亮。 1、菜鸟图库 个人简历模板|WORD文档模板免费下载 - 菜鸟图库 菜鸟图库除了有超多设计类素材之外&#xff0c;还有很多办公类素材&#…...

【CSS】元素居中总结-水平居中、垂直居中、水平垂直居中

【CSS】元素居中一、 水平居中1.行内元素水平居中&#xff08;1&#xff09;text-align2.块级元素水平居中2.1 margin&#xff08;1&#xff09;margin2.2布局&#xff08;1&#xff09;flex justify-content&#xff08;推荐&#xff09;&#xff08;2&#xff09; flexmargin…...

spring实现AOP

文章目录前言一、AOP的底层实现原理二、AOP的两种开发模式1.使用xml配置文件1.1 添加AOP依赖1.2 创建UserService1.3创建UserServiceImpl1.4创建通知类1.5 创建applicationContext.xml&#xff08;添加aop约束&#xff09;1.6 测试2.使用注解开发2.1 创建bean.xml文件配置注解方…...

neovim搭建cpp环境

文章目录Windowns下NeoVim搭建cpp环境NeoVim安装插件vim-plugindentLinevim-airlinectagstagbarcoc.vimWindowns下NeoVim搭建cpp环境 在开发过程中习惯在DIE环境中使用vim作为编辑器&#xff0c;在单独的编辑器也常使用gvim图形化编辑器。最近看到NeoVim的特性及兼容性方面不输…...

SpringBoot AES加密 PKCS7Padding 模式

AES 简介&#xff1a;DES 全称为Data Encryption Standard&#xff0c;即数据加密标准&#xff0c;是一种使用密钥加密的块算法&#xff0c;1977年被美国联邦政府的国家标准局确定为联邦资料处理标准&#xff08;FIPS&#xff09; AES 密码学中的高级加密标准&#xff08;Advan…...

四合一做网站/西安seo招聘

1.如何计算一个函数运行的时间 import time #导入time模块starttime.time() #返回从unix诞生到现在为止的时间&#xff0c;单位是秒 print(start) def haha():print("希望你开心")endtime.time() print(end)print(end-start)输出&#xff1a; RESTART: C:/Users/d…...

做网站老板嫌弃太丑谁的锅/网页设计用什么软件做

1.内存溢出相对于内存泄漏来说&#xff0c;尽管更容易被理解&#xff0c;但是同样的&#xff0c;内存溢出也是引发程序崩溃的罪魁祸首之一。 2.由于GC一致在发展&#xff0c;所有一般情况先&#xff0c;除非应用程序占用的内存增长速度非常快&#xff0c;造成垃圾回收根不上内存…...

简单的手机网址大全/批量优化网站软件

1、JDK &#xff08;Java Development Kit&#xff09;Java开发工具集      从初学者角度来看&#xff0c;采用JDK开发Java程序能够很快理解程序中各部分代码之间的关系&#xff0c;有利于理解Java面向对象的设计思想。JDK的另一个显著特点是随着Java &#xff08;J2EE、J2…...

视频网站如何做引流/手机百度app最新版下载

兄弟姐妹们好&#xff0c;又是好久没有更新了&#xff0c;今天给大家简单介绍代理模式&#xff0c;一个很简单的设计模式&#xff0c;旨在不改变原对象的情况下通过代理对象来控制对原对象的访问。代理模式根据具体情况还可以分为远程代理、虚拟代理、保护代理等&#xff0c;下…...

数据库型网站/在什么网站可以免费

本篇教程探讨了HTML5特性SSE和WebSocket的用法和比较&#xff0c;希望阅读本篇文章以后大家有所收获&#xff0c;帮助大家HTML5CSS3从入门到精通 。<在我们日常开发中&#xff0c;会遇到服务端和客户端的通讯&#xff0c;今天我们就来比较一下HTML5新特性SSE和WebSocket的用…...

西安市阎良区建设局网站/新闻今日头条最新消息

过程赋值&#xff1a;用于对reg型变量赋值&#xff0c;改变寄存器的值或为以后排定改变。 语法 {阻塞性(blocking)赋值} RegisterLValue [ TimingControl] Expression; {非阻塞性(non-blocking)赋值} RegisterLValue < [ TimingControl] Expression; 阻塞&#xff1a;…...