操作系统:12 线程竞争与线程池

news2024/11/22 16:24:52

1 基本概念

① 竞争与同步

        同一个进程中的线程能够共享进程中的绝大多数资源,当他们随意竞争时可能会导致共享资源被破坏、脏数据、不完整、不一致等问题

        通过一些方法让进程中的线程在竞争资源时相互协调,避免出现以上问题,这种手段就称为线程同步技术

② 临界区:

        能够被多个线程访问但又不能同时访问的代码片段称为临界区

③ 临界资源:

        能够被多个进程访问但又不能同时防伪的资源叫做临界资源

        当准备访问临界区和临界资源时,有别的线程和进程正在访问,那么会进入等待

④ 竞态条件:

        当多个线程在临界区内执行且等待,由于线程执行的顺序有随机性,导致结果不确定,就称发生了竞态条件

⑤ 原子操作:

        操作不能够被继续拆解、执行过程中不能被任何方式影响的操作,称为原子操作

2 互斥量(互斥锁)

    注意:linux系统man手册中没有pthread_mutex_xxx系列函数说明,需要额外安装

    sudo apt-get install manpages-posix-dev

    pthread_mutex_t 是一种互斥量数据类型,用于定义互斥量变量

    int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

        功能:初始化一个互斥量

        mutex:要初始化的互斥量

        attr:写NULL使用默认属性即可

        注意:当互斥锁初始化后,默认是开锁状态

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

        注意:可以直接使用PTHREAD_MUTEX_INITIALIZER给互斥锁初始化

    int pthread_mutex_lock(pthread_mutex_t *mutex);

        功能:对一个互斥锁上锁

        mutex:要上锁的互斥量

        返回值:

                成功则上锁并返回继续执行

                失败则阻塞等待,直到互斥锁开锁并成功上锁才返回继续

    int pthread_mutex_trylock(pthread_mutex_t *mutex);

        功能:尝试对一个互斥锁加锁

        mutex:尝试要上锁的互斥量

        返回值:成功返回0,失败返回EBUSY(别线程再整加锁使用) 使用EBUSY加头文件errno.h

    int pthread_mutex_unlock(pthread_mutex_t *mutex);

        功能:对一个互斥锁进行解锁

        mutex:要解锁的互斥量

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    功能:销毁一个互斥锁

3 信号量

        与XSI机制中的信号量原理相似,相当于线程之间使用的计数器,用于控制访问有限的共享资源的线程数

    sem_t是一种信号量数据类型,用于定义信号量变量

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

        功能:初始化信号量

        sem:要初始化的信号量

        pshared:信号量适用范围

                0 只能在本进程使用

                非0 表示该信号量可以被多个进程共享使用(Linux不支持)

        value:最多同时访问共享资源的线程数量

    int sem_wait(sem_t *sem);

        功能:对信号量-1,如果信号量的值为0则阻塞等待

    int sem_trywait(sem_t *sem);

        功能:对信号量尝试-1,如果成功,如果信号量值为0则返回EAGAIN

    int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

        功能:对信号量-1,如果信号量值为0则等待一段时间,超时后返回ETIMEOUT

    int sem_post(sem_t *sem);

        功能:对信号量+1

    int sem_destroy(sem_t *sem);

        功能:销毁信号量

4 死锁

4.1 什么是死锁

        多个进程/线程在使用共享资源时,相互等待对方手中的资源,在得到新资源前不会释放自己手上的资源,最终形成循环等待,这种现象称为死锁

4.2 产生死锁的4大必要条件

① 资源互斥:资源只有两种状态:可用和不可用状态,不能同时使用,同一时刻只能被一个进程或线程使用

② 占有且请求:已经得到了一些资源的进程或线程,继续请求新的资源,并持续占用旧资源

③ 资源不可剥夺:资源在分配给线程或进程后,不能被其它进程或线程强制性夺取,除非占用者主动放弃

④ 环路等待:当死锁发生时,系统中必定存在两个或两个以上的进程线程的执行路线形成环状

    注意:死锁一旦形成,现在的操作系统无法解决已出现的思索情况,因此只能预防死锁的产生

4.3 预防死锁的产生:破坏死锁条件产生的其中一个条件

① 破坏资源互斥:

        想办法让资源共享:共享或增加资源

        缺点:受代码环境或者资金影响无法让资源共享

② 破坏占有且请求:

        采用静态预分配机制,进程或线程可以再运行前一次性申请所有的资源,在资源没有得到全部满足前,不投入运行

        缺点:系统资源会被严重浪费,因为有些资源可能开始时使用,有些资源结束时才使用

③ 破坏资源不可剥夺:

        当一个进程或线程在占用了一个不可被剥夺的资源,并且请求新资源得不到满足时,就释放自己手中的所有资源,等待一段时间后,再重新申请资源

        缺点:该策略实现难度较高,并且释放已或得的资源会导致前一阶段的工作全部失效,反复的申请释放资源会增大CPU的系统开销,浪费内存、时间。

④ 破坏环路等待:

        给每个资源进行编号,进程或线程按照同一个编号顺序依次申请资源,并且只有拿到当前编号的资源后,才能去继续请求下一个编号的资源

        缺点:资源数多,编号难度较高,并且受到实际使用资源顺序情况影响,当增加或删除资源时,又需要重新设计编号方案

4.4 如何判断死锁位置

        画出整个程序的资源分配图

        简化资源分配图

        通过死锁原理:找出出现环路的位置

推荐使用:银行家算法

5 条件变量

        通过条件变量,让线程满足某些条件时,可以自己进入睡眠,也可以在某些条件满足时被其他线程唤醒,一般配合互斥锁

        pthread_cond_t 是一种条件变量数据类型,用于定义条件变量变量

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

        功能:初始化一个条件变量

        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

    注意:可以直接使用PTHREAD_COND_INITIALIZER给条件变量初始化

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

        功能:让调用者睡入条件变量cond,并解锁mutex

    int pthread_cond_signal(pthread_cond_t *cond);

        功能:唤醒睡入cond的其中一个线程

        注意:睡前的互斥锁必须在唤醒前处于打开状态,才可被唤醒并自动加锁

    int pthread_cond_broadcast(pthread_cond_t *cond);

        功能:唤醒所有睡入cond的线程

        注意:睡前的互斥锁必须在唤醒前处于打开状态,才可被唤醒并自动加锁

    int pthread_cond_destroy(pthread_cond_t *cond);

        功能:销毁条件变量

7 生产者消费者模型

        生产者:产生数据的线程

        消费者:使用数据的线程

        仓库:临时存储数据的缓冲区,为了解决生产消费不协调的问题

可能产生的问题:

        生产快于消费:仓库爆满,撑死

        消费快于生产:仓库空虚,饿死

利用条件变量解决问题:

        当仓库缓冲区满的时候,生产者线程睡入条件变量(full),通知消费者线程全部醒来(empty)

        当仓库缓冲区空的时候,消费者线程睡入条件变量(empty),通知生产者线程全部醒来(full)

        根据这个消费者生产者模型,我们可以设计出一个线程池,这是我已经封装好的线程池,有需要可以前往参考:

c语言——线程池https://download.csdn.net/download/snowysc/87774803

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/514728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5月11日作业

思维导图 作业: 作业1: 作业2: 作业3: 作业4: 作业5:

算法设计与分析:枚举和递推的运用

目录 第1关:双关系递推数列 任务描述 相关知识 枚举算法的两种框架 递推算法的实施步骤 问题求解思路 编程要求 测试说明 第1关:双关系递推数列 任务描述 本关任务:运用枚举和递推的基本思想,通过编程计算出双关系递推数…

grafana + influxdb + telegraf构建linux性能监控平台

为了更好的做性能测试过程中监控服务器资源,提供可视化效果,下面介绍一种监控方案: grafana influxdb telegraf , 构建linux性能监控平台 安装3个软件 1.Grafana安装 grafana , 访问各类数据源 , 自定义报表、显示图表等等 , 用于提供界…

微星 B360M MORTAR电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网,转载需注明出处。(下载请直接百度黑果魏叔) 硬件型号驱动情况 主板微星 B360M MORTAR 处理器英特尔 Core i5-9400 2.90GHz 六核已驱动 内存8 GB ( 金士顿 DDR4 2666MHz 8GB )已驱动 硬盘西数 WDS250G3X0C-00SJG0…

mysql高级语句(2)

and or 最左原则 create view视图表:虚拟表或存储查询 没有表结构存储查询语句的结果表 临时表在用户退出或同数据库连接断开就会小时,而视图表不会(就像定义个全局变量)保存的是定义 格式:create view “视图表名…

内测开始了!0penAI GGPT 图片功能、联网功能、音频功能、多模型功能、微调功能

联合两位大佬一起对gpt官方的接口做了整合。 有感兴趣的可以一起开发交流,下文有部分代码讲解。感兴趣的可以加入一起测试玩耍(文末有加入方式)~ 模型介绍 内测内容包括文字生成图片、图片生成图片、联网模式、模型定制、多角色设定等。 1…

mongodb用户权限配置

1.副本集 1.1在主节点创建管理员账号 /etc/mongodb/mongosh-1.8.1-linux-x64/bin/mongosh --port 27017 use admin db.createUser({user:"用户名",pwd:"密码",roles:["root"]}) 只要在主节点创建用户即可,从节点会自动同步数据 …

Verilog语法之generate (for、 if、 case)用法

文章目录 前言一、宏定义二、generate 方法1. generate-if 方法1. generate-case方法 三、小知识(语法模板) 前言 对于同一功能多种不同实现方法的模块代码如何整合到一起呢?当然每种方法作为一个单独的模块使用一个.v 文件保存肯定是没有问…

MySQL 高级(进阶) SQL 语句二

一、表连接查询 MYSQL数据库中的三种连接: inner join(内连接):只返回两个表中联结字段相等的行(有交集的值)left join(左连接):返回包括左表中的所有记录和右表中联结字段相等的记录right join(右连接):…

区间合并(算法)

目录 题目代码实现注意点 题目 给定 n n n 个区间 [ l i , r i ] [l_i, r_i] [li​,ri​],要求合并所有有交集的区间。 注意如果在端点处相交,也算有交集。 输出合并完成后的区间个数。 例如: [ 1 , 3 ] [1,3] [1,3] 和 [ 2 , 6 ] [2,…

【利用AI让知识体系化】深入浅出HTTP(近2w字)

思维导图 文章目录 思维导图1. HTTP基础知识HTTP简介URI和URLHTTP的请求和响应 2. HTTP请求请求方法请求头请求体 3. HTTP响应响应状态码响应头响应体 4. Cookies和SessionCookies的原理和应用Session机制使用Cookies和Session进行用户认证 5. HTTP缓存缓存概述浏览器缓存服务器…

Tomcat源码:连接器与Executor、Connector

前文: 《Tomcat源码:启动类Bootstrap与Catalina的加载》 《Tomcat源码:容器的生命周期管理与事件监听》 《Tomcat源码:StandardServer与StandardService》 《Tomcat源码:Container接口》 《Tomcat源码&#xff1a…

NHWC和NCHW数据排布及转换(模型部署)

1.概念 首先这是两种批量图片的数据存储方式,定义了一批图片在计算机存储空间内的数据存储layout。N表示这批图片的数量,C表示每张图片所包含的通道数,H表示这批图片的像素高度,W表示这批图片的像素宽度。其中C表示的通道数可能有…

被热议的DataOps,到底是什么?

近几年,DevOps的火热程度日渐高涨,同时涌现出了各种Ops,包括DevSecOps、GitOps、AIOps、NoOps、DataOps、MLOps、FeatureOps、ModelOps、FinOps等等。其中,对于企业来说,确保数据以高效和合规的方式使用,Da…

git commit 设置 eslint + pretter 格式化校验

系统版本 node 版本: v14.17.5 npm 版本: 6.14.14 vue-cli 版本: vue/cli 4.5.19 目录 系统版本 1. 新建一个 vue2.X 空项目 2. 安装插件 eslint ,并初始化 eslint 配置,根目录生成 .eslintrc 配置文件 3. 测试 eslint 配置 4. 安装 husky、lint-staged 5. 在package.j…

【Linux从入门到精通】了解冯诺依曼体系结构

本片文章会对冯诺依曼体系结构进行详解。同时,我们对冯诺依曼的理解,不能停留在概念上,要深入到对软件数据流理解上。本片文章同时也会对数据在冯诺依曼结构上的交互进行讲解。希望本篇文章会对你有所所帮助。 文章目录 一、简单认识冯诺依曼…

牛客网面试必刷:BM17 二分查找-I

牛客网面试必刷&#xff1a;BM17 二分查找-I 前言一、什么是二分查找&#xff1f;二、二分查找具体代码1.第一种写法&#xff1a;left < right2.第二种写法&#xff1a;left < right 三、复杂度分析 前言 二分查找是一个常见、基础、难度较低问题&#xff0c;本文记录了…

【JMeter入门】—— JMeter介绍

1、什么是JMeter Apache JMeter是Apache组织开发的基于Java的压力测试工具&#xff0c;用于对软件做压力测试。它最初被设计用于Web应用测试&#xff0c;但后来扩展到其他测试领域。 &#xff08;Apache JMeter是100%纯JAVA桌面应用程序&#xff09;Apache JMeter可以用于对静…

linux系统挂载硬盘

linux系统挂载硬盘 1、背景2、环境3、准备工作4、挂载分区4.1、查看分区信息4.2、创建分区4.3、设置分区格式4.4、创建挂载目录4.5、挂载分区4.6、设置开机自动挂载4.7、验证是否挂载成功 1、背景 日常使用过程中随着系统业务量的新增对磁盘的空间和性能提出了更高的要求&…

功能测试之设计语言测试:功能测试包含哪些测试?分别有什么作用

Web 设计语言版本的差异可以引起客户端或服务器端严重的问题&#xff0c;例如使用哪种版本的HTML 等。当在分布式环境中开发时&#xff0c;开发人员都不在一起&#xff0c;这个问题就显得尤为重要。除了HTML 的版本问题外&#xff0c;不同的脚本语言&#xff0c;例如Java、Java…