Linux 多线程 | 线程的操作、线程库、线程ID

Linux进程和线程

  • 进程是资源分配的基本单位
  • 线程是调度的基本单位
  • 线程共享进程数据,但是也有自己的一部分数据:线程ID(LWP)、一组寄存器、栈、errno、信号屏蔽字、调度优先级

进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

  • 文件描述符表
  • 每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
  • 当前工作目录
  • 用户id和组id

Linux线程控制

之前我们说过Linux下没有真正意义上的线程,而是用进程模拟的线程,所以Linux不会直接提供直接创建线程的接口,它会给我们最多提供轻量级进程的接口,而在用户的视角只认线程,那么在用户和操作系统之间就需要有库来将Linux接口封装,对上给用户提供线程控制的接口。这个库就被称为用户级线程库 -- pthread库,在任何的Linux操作系统下这个库都必须原生自带。因此在编译的时候就需要带有库的链接。

创建线程

pthread_create函数

功能:创建一个新的线程
原型
        int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
参数
        thread:返回线程ID
        attr:设置线程的属性,attr为NULL表示使用默认属性
        start_routine:是个函数地址,线程启动后要执行的函数
        arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码

void* thread_run(void* args) {while (true) {cout << "new thread running" << endl;sleep(1);}return nullptr;
}int main() {pthread_t t; // typedef unsigned long int pthread_t;pthread_create(&t, nullptr, thread_run, nullptr);while (true) {cout << "main thread running, newthread id : " << t << endl;sleep(1);}
}

上面就是一段简单的多线程代码,它执行的结果如图所示,可以看出线程的id的数很奇怪与我们之前说的LWP不一样,这个问题稍后我们会进行解答。

可以通过pthread_self(void);函数来获取对应的线程ID。

线程终止

如果需要只终止某个线程而不终止整个进程,可以有三种方法:

  1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
  2. 线程可以调用pthread_ exit终止自己。
  3. 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程。

pthread_exit函数

功能:线程终止

原型
        void pthread_exit(void *value_ptr);
参数
        value_ptr:value_ptr不要指向一个局部变量。
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)

pthread_cancel函数

功能:取消一个执行中的线程
原型
        int pthread_cancel(pthread_t thread);
参数
        thread:线程ID
返回值:成功返回0;失败返回错误码

线程等待

为什么需要线程等待?

  • 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
  • 创建新的线程不会复用刚才退出线程的地址空间。

功能:等待线程结束
原型
        int pthread_join(pthread_t thread, void **value_ptr);
参数
        thread:线程ID
        value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

  1. 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值。
  2. 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_ CANCELED。
  3. 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
  4. 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数。

分离线程

默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

int pthread_detach(pthread_t thread);
可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离:
        pthread_detach(pthread_self());

joinable和分离是冲突的,一个线程不能既是joinable又是分离的。

线程库、线程ID等概念

我们使用的线程库是真实存在的,通过前面的知识我们知道库就会被加载虚拟地址空间中的共享区中,而进程中的线程可以随时访问库中的代码和数据 -- 关于线程的管理,创建类似管理线程的TCB。举例来说,在学习文件系统的时候,每个文件有自己的文件描述符表,但是无论是在使用c的时候,我们都没有直接使用fd,而是使用的库给我们提供的fopen、fclose等等。同样在线程这里,在创建线程的时候就有LWP,为了更好的管理LWP,就有了共享库中的TCB。因此这个库被称为用户级线程库。

 所有新线程都有自己独立的栈结构,主线程用的是进程系统栈,新线程用的是库中提供的栈。

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

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

相关文章

Linux(一)

介绍 常见的操作系统(windows、IOS、Android、MacOS, Linux, Unix)&#xff1b; 一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发已经得到业界的认可&#xff1b;目前很多企业级的项目(c/c/php/python/java/go)都会部署到 Linux/unix 系统上。 吉祥物 …

遗失的源代码之回归之路的探索与实践

背景 最近比较突然被安排接手一个项目,该项目的情况如下 原生和RN结合的混合开发模式组件化开发,有很多基础组件以及业务组件但是在梳理项目依赖时发现了个别组件源码不全的情况,于是写了个cli用于对比两个版本产物文件,生成差异结果以便于快速进行源码找回恢复。 结果如下…

2、安全开发-Python-Socket编程端口探针域名爆破反弹Shell编码免杀

用途&#xff1a;个人学习笔记&#xff0c;欢迎指正&#xff01; 目录 主要内容&#xff1a; 一、端口扫描(未开防火墙情况) 1、Python关键代码: 2、完整代码&#xff1a;多线程配合Queue进行全端口扫描 二、子域名扫描 三、客户端&#xff0c;服务端Socket编程通信cmd命…

SpringCloud-微服务项目架构

在当今软件开发领域&#xff0c;微服务架构正成为构建灵活、可伸缩、独立部署的应用的首选&#xff0c;微服务架构作为一种灵活而强大的设计模式&#xff0c;通过将系统拆分为独立的、自治的服务&#xff0c;使得应用更容易维护、扩展和升级。本文将探讨微服务项目架构的关键特…

数据在内存中的存储(上)

1. 整数在内存中的存储 整数的2进制表示方法有三种&#xff1a;即原码、反码和补码 三种表示方法均有符号位和数值位两部分&#xff0c;符号位都是用0表示“正”&#xff0c;用1表示“负”&#xff0c;而数值位最 高位的一位是被当做符号位&#xff0c;剩余的都是数值位。 正…

流畅的Python(七)-函数装饰器和闭包

一、核心要义 主要解释函数装饰器的工作原理&#xff0c;包括最简单的注册装饰器和较复杂的参数化装饰器。同时&#xff0c;因为装饰器的实现依赖于闭包&#xff0c;因此会首先介绍闭包存在的原因和工作原理。 二、代码示例 1、变量作用域规则 #!/usr/bin/env python # -*-…

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key   登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…

Python—数据可视化Seaborn大全:参数详解与实战案例全解析【第52篇—python:Seaborn大全】

文章目录 Seaborn库常用绘图详解与实战引言安装与导入一、散点图参数说明实战案例 二、直方图参数说明实战案例 三、线性关系图参数说明实战案例 四、热力图参数说明实战案例 五、分布图参数说明实战案例 六、箱线图参数说明实战案例 七、联合分布图参数说明实战案例 八、小提琴…

AJAX-常用请求方法和数据提交

常用请求方法 请求方法&#xff1a;对服务器资源&#xff0c;要执行的操作 axios请求配置 url&#xff1a;请求的URL网址 method&#xff1a;请求的方法&#xff0c;如果是GET可以省略&#xff1b;不用区分大小写 data&#xff1a;提交数据 axios({url:目标资源地址,method…

ES6-数组的解构赋值

一、数组的解构赋值的规律 - 只要等号两边的模式相同&#xff0c;左边的变量就会被赋予对应的值二、数组的解构赋值的例子讲解 1&#xff09;简单的示例&#xff08;完整的解构赋值&#xff09; 示例 //基本的模式匹配 // a&#xff0c;b,c依次和1&#xff0c;2&#xff0c…

freeswitch对接FunASR实时语音听写

1、镜像启动 通过下述命令拉取并启动FunASR软件包的docker镜像&#xff1a; sudo docker pull \registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.7 mkdir -p ./funasr-runtime-resources/models sudo docker run -p 10096:10095 -i…

ctfshow web-77

开启环境: 先直接用伪协议获取 flag 位置。 c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). );} exit(0); ?> 发现 flag36x.txt 文件。同时根目录下还有 readflag&#xff0c;估计需要调用 readflag 获…