Linux之线程

Linux之线程

  • 线程之形
  • 线程接口
  • 线程安全
    • 互斥锁
    • 条件变量&信号量
    • 生产者与消费者模型
    • 线程池

线程之形

进程是资源分配的基本单位,而线程是进程内部的一个执行单元,也是 CPU 调度的基本单位。
线程之间共享进程地址空间、文件描述符与信号处理,但也有独立资源:寄存器、栈、线程ID和调度优先级等。
线程切换由于地址空间相同,上下文切换时寄存器切换和内存地址缓存诸如页表缓存TLB(快表)及硬件缓存切换成本比进程切换低得多。
Linux下的线程并非标准的、独立于进程实现的线程(参见windows实现线程),而是通过pthread库封装了轻量级进程LWP(light weight process)来模拟线程。具体的说法,详见下文。

说Linux的线程是用LWP模拟的意思是,Linux利用了进程的概念和机制来实现线程的功能,通过让不同的线程共享某些资源来达到所谓的“轻量级”效果。这种方式使得线程既能够享受到与进程相似的隔离性和保护性,又能够在同一程序内部高效地进行数据交换和通信。另,ps -aL查看LWP即线程信息。之前的ps -axj只能查看进程级别信息。

线程接口

  • 线程创建:int pthread_create(pthread_t *restrict thread,const pthread_attr_t *restrict attr,void *(*start_routine)(void *),void *restrict arg);,thread输出型参数,存储用户层线程ID;attr线程属性,给NULL即可;start_routine线程执行函数;arg传给前者的参数。

pthread_create是glibc库提供的接口,它实际上,调用mmap()在堆区分配struct pthread(线程控制块 TCB,库描述与管理线程的结构体,存储内核级tid,线程栈指针与大小,TLS指针和线程状态、返回值等)和固定大小的线程栈以及线程局部存储(TLS,存储私有变量如errno),再调用int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );fn即线程执行函数,arg其参数,child_stack传mmap出来的线程栈栈底地址,flags选项较多自行了解。然后,内核再创建一个task_struct描述新线程,其mm_struct指向同一个地址空间,pid实为内核级tid(t即thread),tgid线程组id为进程id(主线程tid和pid和进程pid是同一个)。而mmap区的struct pthread的起始虚拟地址即为用户层线程ID,作为上面函数第一个参数带出。

线程局部存储,在全局内置类型变量前加__thread修饰,使之成为各个线程局部存储区变量而非全局区变量。另外,pthread_setname_np(pthread_t,const char*)可将变量放至局部存储,实现取名字;pthread_getname_np(pthread_t,char*,size_t)得之。

  • 线程终止:void pthread_exit(void *retval);终止当前线程,retval即线程返回值。注意,exit()终止进程。
  • 等待线程结束:int pthread_join(pthread_t thread, void **retval);阻塞等待指定ID线程,retval带出上面的返回值。而线程返回值在终止后会被存放在struct pthread里,等join时拿出来。
  • 线程分离:int pthread_detach(pthread_t thread);将指定线程置于分离状态,系统会在该线程结束后自动回收其资源而无需等待。可搭配pthread_t pthread_self(void);分离自己。

线程终止还包括在执行函数return和线程取消int pthread_cancel(pthread_t thread);,后者给join的retval为-1。如果调用join则会释放其struct pthread和线程栈以及task_struct,如果detach则结束自动销毁它们。注意,动态开辟的堆区内存需要手动释放,否则内存泄漏。

线程安全

线程安全指多个线程并发访问共享资源时不出因为线程切换等引发的问题。通常需要互斥锁、条件变量等方案来保证。

互斥锁

临界资源是一次仅允许一个执行流使用的共享资源,临界区是访问临界资源的那段代码,互斥是多线程并发竞争式访问临界资源时、同一时间只有一个线程能进入临界区的情况。
互斥锁实际上就是同一时刻只让拿到锁的线程进入临界区,让并行变成串行访问。
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);初始化锁,后参为属性通常NULL,全局锁也可用PTHREAD_MUTEX_INITIALIZER初始化;pthread_mutex_lock(pthread_mutex_t *mutex);阻塞式获取锁,非阻塞与定时自行了解;pthread_mutex_unlock(pthread_mutex_t *mutex);释放锁;pthread_mutex_destroy(pthread_mutex_t *mutex);销毁锁。
锁本身作为临界资源被访问,多线程并发去lock时是怎么保证互斥的?
伪代码如下:

lock:movb $0, %al//原子性将al写入0xchgb %al, mutex//原子性交换锁和al的内容,锁初始为1if(al寄存器的内容 > 0)return 0;//抢到锁了else挂起等待;goto lock;
unlock:movb $1, mutex//原子唤醒等待Mutex的线程;return 0;

原子性指一个操作只有01两态,即有无两态,无中间态。原子操作就是遵守原子性的操作。上面锁的代码中写入movb和交换xchgb为原子操作,如果一个线程抢到了锁,则mutex里为0,al里为1,其他线程永远拿不到这个1,因为mutex里为0,除非该线程unlock,再把1放回mutex。
关于RAII风格的lockguard,即构造lock mutex,析构unlock之。

条件变量&信号量

同步值在互斥前提下,多线程按序访问临界资源。
条件变量Condition即允许多线程排队等待某个条件变量就绪,等候通知从而按序访问临界资源。
pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);初始化条件变量,也可PTHREAD_COND_INITIALIZER;pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);等待条件,后参为互斥锁,该函数会1先解锁,既防止死锁(因为其他线程无法拿到锁并修改条件、发出通知)也提高性能,允许其他线程访问临界资源,2阻塞等待,进入条件变量的等待队列中,3一旦被唤醒成功,重新获取并上原来的锁。该函数应在while(检测条件)内部使用,因为存在伪唤醒(比如因为系统中断或异常处理、内核优化等导致调度变化)或等待失败、函数返回的情况;pthread_cond_signal(pthread_cond_t *cond);唤醒一个等待该条件的线程;pthread_cond_broadcast(pthread_cond_t *cond);唤醒所有;pthread_cond_destroy(pthread_cond_t *cond);销毁之。
信号量Semaphore(此处是POSIX标准下的)是一种预定机制,想象去电影院前先买票再排队入场,信号量就是票,所有人互斥(通过原子操作保证)抢票来预定座位,然后排队进场看电影。
int sem_init(sem_t *sem, int pshared, unsigned int value);初始化信号量,二参0为线程间共享、非0进程间共享,三参为初始值;sem_wait(sem_t *sem); // 如果信号量值大于0,则减1;否则阻塞P操作,申请信号量即信号量减1,类比买票;sem_post(sem_t *sem); V操作,释放信号量即信号量加1,类比退票或放票。

生产者与消费者模型

多个生产者并行生产商品,串行投入商品至超市,多个消费者串行拿取商品出超市,并行消费商品。
3种关系,生产者之间互斥,消费者之间互斥,生消之间互斥且同步;2种角色,生消;1个交易场所,以特定结构构成的内存空间。
可以通过阻塞队列存放任务+锁+条件变量同步等待(生产者生产任务了通知等待的消费者、满了等待消费者通知,消费者消费任务了通知等待的生产者、完了等待生产者通知)实现,也可以通过环形队列存放任务+锁+信号量(生产者对空位量P操作、任务量V操作,消费者对空位量V操作、任务量P操作)实现。

线程池

提前创造一批线程,等待任务到来,来一个召唤一个线程去处理一个。可采用锁+条件变量的方式实现。


最后两个模块的代码具体实现,还没考虑好是否要呈现以及如果要呈现的话要怎么呈现,所以只提供了思路。
线程over,终于进入网络部分了,理论系统学习生涯结束指日可待啊!

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

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

相关文章

snail-job的oracle sql(oracle 11g)

官网版本的oracle sql中有自增主键,oracle 11g并不支持,所以改成新建索引和触发器的方式自增主键。(tip:snail-job的最新版本1.0.0必须使用JDK17, jdk8会报错,所以最后没用起来) /*SnailJob Dat…

Windows VMWare Centos Docker部署Nginx并配置对Springboot应用的访问代理

前置博文 Windows VMWare Centos环境下安装Docker并配置MySqlhttps://blog.csdn.net/u013224722/article/details/148928081 Windows VMWare Centos Docker部署Springboot应用https://blog.csdn.net/u013224722/article/details/148958480 # 将已存在的容器设置为宿主机重启后…

暑期数据结构第一天

暑期数据结构第一天 数据元素与数据对象 数据元素--组成数据的基本单位 与数据的关系:是集合的个体 数据对象--性质相同的数据元素的集合 与数据的关系:集合的子集 逻辑结构 (1)线性结构,所有结点都最多有一个直…

vsCode 扩展中 package.nls.json 文件的作用国际化支持

package.nls.json 代表英文语言文件 {"command.favourite.addtofavourite": "Add to Favourite","command.favourite.deletefavourite": "Remove from Favourite","command.favourite.moveup": "Move Up" } 在 …

结构型智能科技的关键可行性——信息型智能向结构型智能的转换(提纲)

结构型智能科技的关键可行性 ——信息型智能向结构型智能的转换 1.信息型智能科技概述 1.1传统计算机科技的信息型继承者 1.2 信息型智能环境 1.3信息型智能主体 1.4机器学习创造的智能 1.5信息型智能科技的问题 2.结构型智能科技概述 2.1传统计算机科技向真实生命结构…

Excel 数据合并助手SheetDataMerge智能识别同类数据,销售报表处理提升效率

各位Excel小能手们!今天给大家介绍个超厉害的玩意儿——SheetDataMerge,这可是专注Excel数据处理的实用工具!它就像个数据小管家,核心功能就是智能合并工作表里的同类数据。 软件下载地址安装包 它有多牛呢?能自动识别…

AIStarter平台使用指南:如何一键卸载已下载的AI项目(最新版操作教程)

如果你正在使用 AIStarter 平台,但不知道如何卸载不再需要的 AI 项目,那么这篇简明教程将为你提供清晰的操作指引。 AIStarter 是由知名创作者“熊哥”打造的一款 AI 工具启动器平台,旨在帮助用户快速部署和运行各类 AI 项目。随着平台不断更…

项目中大表治理方案实践

一、业务背景 目前生产库数据库服务器数据存储达到了13T,其中license_spart表数据量达到了200亿,占用7.5T,空间占用率达到54%。而且这张表每年数据增长量达到30亿。其中有效VALID数据占20亿,无效数据INVALID占180亿。由于业务上有…

快应用(QuickApp)技术解析与UniApp跨端开发生态探秘优雅草卓伊凡

快应用(QuickApp)技术解析与UniApp跨端开发生态探秘优雅草卓伊凡引言:一场由快应用引发的技术辩论近日,优雅草科技的资深开发者卓伊凡在与甲方的一次项目沟通中,因技术选型问题展开了激烈讨论。甲方对快应用&#xff0…

《Font Awesome 参考手册》

《Font Awesome 参考手册》 引言 Font Awesome 是一个功能丰富的图标库,旨在帮助设计师和开发者快速地在网页上添加图标。它提供了超过700个矢量图标,并且支持响应式设计。本文将为您详细介绍 Font Awesome 的使用方法、图标分类、图标定制以及与 CSS 的结合。 一、Font A…

Linux基本命令篇 —— uname命令

uname命令是Linux系统中用于显示系统信息的实用工具,它可以提供关于操作系统、内核版本、硬件架构等重要信息。下面我将详细介绍这个命令的用法和常见应用场景。 目录 一、基本语法 二、常用选项 三、使用示例 显示所有系统信息(最常用) …

React Native 开发环境搭建--window--android

官网: https://reactnative.cn/docs/environment-setup 必须安装的 node, JDK ,android Studio 安装node 以前装了nvm, 用nvm install 18.0.0 就可以了 安装JDK 1、下载 ---- 我安装的是11 【JAVA17下载传送门】 注意!!!1 …

ODS 系统是什么?企业为什么需要搭建 ODS?

目录 一、ODS 系统基础认知:先弄明白它是啥 1. 什么是 ODS 系统? 2. ODS 系统的起源 3. ODS 系统的特点 二、ODS 系统能干啥?核心功能解析 1. 数据集成 2. 数据清洗和转换 3. 实时数据更新 4. 数据查询和分析 三、企业为什么非得搭…

通过网页调用身份证阅读器http websocket方法-华视电子————仙盟创梦IDE

1.安装全浏览器网页专用监控软件 2.安装后 3.配置web接口 4.测试读取 5.驱动监控地址 时间段内读取身份证:如超时时间10000ms,则在点击按钮10秒内,放上身份证就可以读成功,超时返回失败; 读身份证:把身份证放上去后点击读卡,读成功,再次读卡需要将身份证拿起来再放回去; 不拿…

Spring Cloud 前端调用后端接口方式

在 Spring Cloud 微服务架构中,前端调用后端接口通常不直接通过 Eureka,而是通过以下两种核心方式实现: 一、前端直接调用后端服务(需解决跨域和地址管理问题) 1. AJAX 直接调用 前端通过 HTTP 请求(如 …

【stm32】HAL库开发——CubeMX配置RTC,单片机工作模式和看门狗

目录 一、CubeMX配置RTC 1.RTC实时重要一环——BKP 寄存器 2.RTC实时时钟 2.1打开RTC并设置时间 2.2打开外部低速时钟 2.3代码实现: 二、单片机工作模式 1.低功耗睡眠模式(Sleep) 2.低功耗停止模式(Stop) 3.低功耗待机模式(StandBy) 三、看门狗 1.独立看…

9.Docker的容器数据卷使用(挂载)

什么是容器数据卷技术? 到这里,我算是入门docker了! docker的理念:将环境和应用打包成一个镜像!直接安装就能使用 如果数据都在容器中,那么我们一旦将容器删除,数据就会丢失!因为…

使用 TCollector 写入 TDengine

TCollector 是 openTSDB 的一部分,它用来采集客户端日志发送给数据库。 只需要将 TCollector 的配置修改指向运行 taosAdapter 的服务器域名(或 IP 地址)和相应端口即可将 TCollector 采集的数据存在到 TDengine 中,可以充分利用…

高斯消元法详解

文章目录 概念用法特殊情况 我的奇怪方法 概念 什么是高斯消元?让我们看一看 OI-Wiki 的解释: 高斯消元法(Gauss–Jordan elimination)是求解线性方程组的经典算法,它在当代数学中有着重要的地位和价值,是线性代数课…

暴雨服务器成功中标华中科技大学集成电路学院服务器采购项目

近日,武汉暴雨信息发展有限公司在激烈的竞争中脱颖而出,成功中标华中科技大学集成电路学院的服务器采购项目。此次中标产品为暴雨旗下的塔式重装AM400服务器,这一成果标志着暴雨信息在高性能计算领域的卓越实力得到了高校科研机构的高度认可。…