【linux】线程(二)

10. pthread_t 类型

注意:

  1. 每一个线程的库级别的tcb的起始地址,就是线程的 tid
  2. 每一个线程都有自己独立的栈结构
  3. 线程和线程之间,也是可以被其他线程看到并访问的(比如全局函数)

代码

如果想要进程拥有私人的全局变量(即线程库里面的线程局部存储):

__stread 修饰 变量(只能是内置类型的,不能是自定义类型的) ,如:

__stread int val

注意:

__stread 是编译选项

代码

11. linux线程互斥

(一)进程线程间的互斥相关背景概念

  1. 临界资源:多线程执行流共享的资源就叫做临界资源
  2. 临界区:每个线程内部,访问临界资源的代码,就叫做临界区
  3. 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
  4. 原子性(后面讨论如何实现):不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成
  5. 多线程并发访问共享资源的时候,容易发生数据不一致问题

抢票举例

if ( tickets > 0) // 判断

{

tickets--; //抢到票了

}

注意:

由于是 tickets-- 这一步是三条汇编指令去执行

  1. 把 tickets 拷贝到CPU寄存器中
  2. CPU寄存器的值--
  3. CPU寄存器的值拷贝到内存

发生错误可能原因:

  1. if 语句判断条件为真以后,代码可以并发的切换到其他线程
  2. tickets-- 操作本身就不是一个原子操作

注意:

要解决数据不一致问题,需要做到三点:

  1. 代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
  2. 如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临界区
  3. 如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区

要做到这三点,本质上就是需要一把锁。Linux上提供的这把锁叫互斥量

(二)互斥量

互斥量相关函数

初始化互斥量

初始化互斥量有两种方法:

1. 静态分配:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

注意:

此时不需要对 pthread_mutex_t 类型变量做初始化和销毁处理(即不需要调用 pthread_mutex_init 和 pthread_mutex_destroy 函数)

2. 动态分配:

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict

attr);

参数:

mutex:要初始化的互斥量

attr:互斥量的属性,一般设置成NULL

注意:

这个函数一定要搭配 pthread_mutex_destroy一起使用

销毁互斥量

int pthread_mutex_destroy(pthread_mutex_t *mutex);

注意:

  1. 不要销毁一个已经加锁的互斥量
  2. 已经销毁的互斥量,要确保后面不会有线程再尝试加锁

互斥量加锁和解锁

加锁 :int pthread_mutex_lock(pthread_mutex_t *mutex);

解锁 :int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值:成功返回0,失败返回错误号

注意:

1.  调用 pthread_ lock 时,可能会遇到以下情况:

互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功

互斥量处于加锁状态,该线程会被阻塞,执行流处于被挂起,等待操作系统唤醒(即互斥量解锁了)

2.  哪个线程都可以对互斥量解锁,和加锁的线程是哪个无关

3.  即使只有一个线程,也可能由于操作不当,被阻塞挂起(比如:调用了两次加锁)

4.  如果申请了锁的资源,一定要把它释放掉

5.  加了锁的临界区的代码发生线程切换,也不会影响结果的正确

(三)加锁

  1. 加锁的本质:用时间来换安全
  2. 加锁的表现:线程对于临界区代码串行执行
  3. 加锁的原则:尽量要保证临界区的代码少

注意:

  1. 纯互斥环境下,如果锁分配的不合理,容易导致其他线程的饥饿问题(线程对锁的竞争能力可能不同,比如一个线程释放了锁,又能立刻拿到锁资源,导致其他线程一直阻塞)
  2. 不一定是有互斥,必有饥饿,纯互 m斥的场景,就用互斥
  3. 解决饥饿:让所有的线程获取锁资源,是按一定的顺序获取 --------- 叫同步

(三)互斥性原理

锁也是共享资源,为了维护其他临界资源,应该先保护自己的资源

锁的实现原理:

为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令(在硬件芯片上都有对应的指令集),该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的 总线周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期

把lock和unlock的伪代码改一下:

 注意:

  1. 寄存器不等于寄存器的内容(寄存器实际上很多时候,得到的数据是上下文数据)
  2. 线程在执行的时候,将共享资源,加载到CPU寄存器的本质:把数据的内容,变成自己的上下文(发生线程切换,上下文数据需要被保存回线程,从而变成线程独有的资源 ---- 线程局部储存)

12. 可重入和 线程安全

(一)概念

  1. 线程安全:多个线程并发同一段代码时,不会出现不同的结果。常见对全局变量或者静态变量进行操作,并且没有锁保护的情况下,会出现该问题
  2. 重入:同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他的执行流再次进入,我们称之为重入。一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入函数,否则,是不可重入函数。

(二)常见的线程不安全的情况

  • 不保护共享变量的函数
  • 函数状态随着被调用,状态发生变化的函数
  • 返回指向静态变量指针的函数
  • 调用线程不安全函数的函数

(三)常见的线程安全的情况

  • 每个线程对全局变量或者静态变量只有读取的权限,而没有写入的权限,一般来说这些线程是安全的
  • 类或者接口对于线程来说都是原子操作
  • 多个线程之间的切换不会导致该接口的执行结果存在二义性

(四)常见不可重入的情况

  • 调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的
  • 调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构
  • 可重入函数体内使用了静态的数据结构

(五)常见可重入的情况

  • 不使用全局变量或静态变量
  • 不使用用malloc或者new开辟出的空间
  • 不调用不可重入函数
  • 不返回静态或全局数据,所有数据都有函数的调用者提供
  • 使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据

(六)可重入与线程安全联系

  • 函数是可重入的,那就是线程安全的
  • 函数是不可重入的,那就不能由多个线程使用,有可能引发线程安全问题
  • 如果一个函数中有全局变量,那么这个函数既不是线程安全也不是可重入的

(七)可重入与线程安全区别

  • 可重入函数是线程安全函数的一种
  • 线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
  • 如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会产生死锁,因此是不可重入的

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

拥抱“新市民” ,数字银行的“谋与变”

【潮汐商业评论/原创】 数字银行,既是金融行业的创新物种,其在发展的过程中也彰显着普惠金融的基因。 “我劝你买点银行理财吧,选一家靠谱的银行就是最靠谱的理财方式了,踏踏实实地把钱存银行里面不会有问题的”,周日…

SpringBoot篇(二、制作SpringBoot程序)

目录 一、代码位置 二、四种方式 1. IDEA联网版 2. 官网 3. 阿里云 4. 手动 五、在IDEA中隐藏指定文件/文件夹 六、复制工程-快速操作 七、更改引导类别名 一、代码位置 二、四种方式 1. IDEA联网版 2. 官网 官网制作:Spring Boot 3. 阿里云 阿里云版制…

react18中的计算属性及useMemo的性能优化技巧

react18里面的计算属性和使用useMemo来提升组件性能的方法 计算属性 实现效果 代码实现 函数式组件极简洁的实现,就这样 import { useState } from "react"; function FullName() {const [firstName, setFirstName] useState("");const [la…

AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】

Mac分享吧 文章目录 AlDente Pro for Mac 充电限制保护工具 安装完成,软件打开效果一、AlDente Pro for Mac 充电限制保护工具 Mac电脑版——v1.28.41️⃣:下载软件2️⃣:安装软件,将安装包从左侧拖入右侧文件夹中,等…

c++初阶--string类(使用)

大家好,许久不见,今天我们来学习c中的string类,在这一部分,我们首先应该学习一下string类的用法,然后再试着自己去实现一下string类。 在这里,我使用的是这个网站来查找的string类,这里面的内容…

Web,RESTful API 在微服务中的作用是什么?

大家好,我是锋哥。今天分享关于【Web,RESTful API 在微服务中的作用是什么?】面试题?希望对大家有帮助; Web,RESTful API 在微服务中的作用是什么? 在微服务架构中,Web 和 RESTful …

react18中如何实现同步的setState来实现所见即所得的效果

在react项目中,实现添加列表项,最后一项自动显示在可视区域范围!! 实现效果 代码实现 import { useState, useRef } from "react"; import { flushSync } from "react-dom"; function FlushSyncRef() {con…

基于SSM网络在线考试系统的设计

管理员账户功能包括:系统首页,个人中心,学生管理,在线考试管理,试题管理,考试管理,系统管理 前台账号功能包括:系统首页,个人中心,在线考试,公告信…

word删除空白页 | 亲测有效

想要删掉word里面的末尾空白页,但是按了delete之后也没有用 找了很久找到了以下亲测有效的方法 1. 通过鼠标右键在要删除的空白页面处显示段落标记 2. 在字号输入01,按ENTER(回车键) 3.成功删除了!!

ECharts饼图-饼图34,附视频讲解与代码下载

引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我将带大家一起实现一个饼图图表,通过该图表我们可以直观地展示和分析数据。此外,我还将提供详…

模型实战(27)之 YOLO11 推理、验证及训练自己的数据集

模型实战(27)之 YOLO11推理、验证及训练自己的数据集 2024年10.17,YOLO11是近期十月份刚经ultralytics团队更新优化发布的视觉算法深度学习网络模型,其网络模型结构代码实现也采用了比较新的Python数据结构,所以虚拟环境搭建安装包也比较新,经过多次踩坑,把关键环节记录…

电子便签:从偶像剧到职场的实用转变

在快节奏的现代生活中,便签已经成为了我们不可或缺的助手,无论是纸质的还是电子的,它们都以小巧的“身躯”承载着我们的日常记忆和待办事项。从偶像剧中常见的“便利贴”女孩形象,到如今电子便签的普及,它们帮助我们捕…

百度搜索竞价推广有必要做吗?怎么做效果好!

百度竞价推广,有的行业适合,有的行业则不行,下面我给大家分享下哪些行业可以。 如果是招商加盟、招代理商、招经销商,或者是高客单价咨询服务费,甚至是找合作方、渠道方的企业主都可以投放竞价推广。 总之一句话&…

网络安全的五大误区,你中招了吗?

在数字化时代,网络安全问题日益突出,许多人在使用网络过程中存在一些误区,导致个人信息泄露、财产损失等问题。本文将为您揭示网络安全的五大误区,帮助您提高安全防范意识。 误区一:使用复杂密码就一定安全 许多人认为…

基于SpringBoot+Vue+uniapp微信小程序的垃圾分类系统的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

万户ezEIP企业管理系统 productlist.aspx SQL注入漏洞复现

0x01 产品简介 万户ezEIP是一种企业资源规划软件,旨在帮助企业管理其各个方面的业务流程。它提供了一套集成的解决方案,涵盖了财务、供应链管理、销售和市场营销、人力资源等各个领域。 0x02 漏洞概述 万户ezEIP企业管理系统 productlist.aspx 接口存在SQL注入漏洞,未经身…

11_原始值的响应式方案-ref

目录 引入 ref解决响应丢失的问题自动脱 ref 引入 ref 在之前实现的 reactive 方法,其代理的目标必须是一个非原始值才行,例如: let str vue // 无法拦截 str 的修改 str vue3上述这个例子表达的意思就是,我们还缺少一个能够对…

ZYNQ:流水灯实验

实验目的 PL_LED0 和 PL_LED1 连接到 ZYNQ 的 PL 端,PL_LED0 和 PL_LED1循环往复产生流水灯的效果,流水间隔时间为 0.5s。 原理图 程序设计 本次实验是需要实现两个LED的循环熄灭点亮,时间间隔是0.5S,对时间间隔的控制使用计数器来完成。本…

第十九课:Python学习之继承

继承 目标 单继承多继承 面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中继承 实现代码的重用,相同的代码不需要重复的编写多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度 01. 单继承 …

安装buildkit,并使用buildkit构建containerd镜像

背景 因为K8s抛弃Docker了,所以就只装了个containerd,这样就需要一个单独的镜像构建工具了,就用了buildkit,这也是Docker公司扶持的,他们公司的人出来搞的开源工具,官网在 https://github.com/moby/buildkit 简介 服务端为buildkitd,负责和runc或containerd后端连接干活,目前…