Linux的线程概念与控制

目录

1、Linux的线程概念

1.1 什么是线程

1.2 分页式存储管理

1.3 线程的优点

1.4 线程的缺点

3、Linux的线程控制

3.1 POSIX线程库

3.2 线程创建

3.3 线程退出

3.4 线程等待

3.5 线程分离


1、Linux的线程概念

1.1 什么是线程

  • 首先Linux内核不区分"进程"和"线程",统一用task_struct管理CPU处理的一个个task_struct
  • 进程 = 1个或多个task_struct(PCB) + 代码和数据
  • 线程(轻量级进程) = 1个task_struct(PCB) (它通过指针共享了其所属进程代码和数据
  • 我们之前讲的传统的进程是一个主线程。
  • 一个进程的多个task_struct(PCB),被认为是多个轻量级进程,主轻量级进程的id即lwp(light weight peocess)与进程的pid相同。
  • 进程强调独占,部分共享;线程强调共享,部分独占。

1.2 分页式存储管理

  • 磁盘I/O虚拟内存(进程地址空间)的单位是""(逻辑(4KB))。OS,使用数组管理。
  • 物理内存的单位是"页框"(物理(4KB))。OS,使用数组管理。

  • 一个进程不可能把所有内存4G(1024个页表 * 1024个页框 * 页框大小4KB)用完,所以页表的大小远小于4MB,所以一个进程只有一张页目录 + n张页表。
  • 页目录里的元素称为页目录项,页表里的元素称为页表项。
  • 页表项里面存页框的起始地址,由于框的起始地址都是4KB的整数倍,所以地址的低12位,没有用上,就作为控制位高20位,正好完美覆盖了32位CPU最大的4GB物理地址空间(1024(10位) * 1024(10位) * 指向一个4KB)。 那页目录项里面存页表的起始地址呢?也是因为页表的起始地址都是4KB的整数倍?是的,地址的低12位,也作为控制位
  • 画外音:因此,整个页目录理论上最大可以管理 1024 * 4GB(对应1024个页表) = 4TB 的虚拟地址空间,但是CPU跟不上,哈哈。

1.3 线程的优点

都是由于共享所属进程虚拟内存空间和系统资源

  • 创建与销毁开销小
  • 切换效率高。共享地址空间,TLB(快表)与缓存有效。
  • 资源占用少
  • 通信与数据共享便捷

1.4 线程的缺点

  • 性能损失。多进程增加了额外的同步和管理开销。上下文切换和调度算法和竞争锁。
  • 健壮性/稳定性降低。一个线程崩溃,会导致整个进程中的所有线程崩溃。
  • 缺乏访问控制在一个进程中所有线程共享相同的访问权限。操作系统安全权限(如文件访问权限、用户ID等)的设置对象是进程,而不是线程。
  • 编程与调试难度极高

3、Linux的线程控制

3.1 POSIX线程库

  • 因为用户区分线程,而Linux内核只认task_struct(共享代码和数据,就是线程之分,代码和数据独立,就是进程之分),需要线程相关的接口,所以pthread库(POSIX线程库)封装内核创建共享资源任务的系统调用并提供了一套标准、易用的线程管理接口
  • 在Linux中,C++11,就封装了pthread库。
  • 每个线程都有独立的栈空间(调用不同的函数,创建独立的栈帧),主线程虚拟地址空间里的新线程动态库mmap出来;线程局部存储,使用__thread修饰(全局的或静态的)内置类型或部分指针,使数据独立。
  • Linux中,pthread_setname_np()pthread_getname_np() glibc提供的函数,它们通过系统调用(如 prctl())请求内核将用户提供的字符串写入或读出指定线程的内核结构体 struct task_struct 的 comm 字段。这是一个存储在内核空间的、全局可见的线程标识符。由于其修改和读取必须通过内核进行,由内核保证操作的原子性,因此不存在并发问题。

3.2 线程创建

  • int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                              void *(*start_routine) (void *), void *arg);
  1. pthread_t *thread线程id,输出型参数。pthread库彻底封装了轻量级进程,线程的id不是lwp,而是在库中对应管理块起始虚拟地址pthread_t pthread_self(void);,获取当前线程的id。
  2. const pthread_attr_t *attr设置线程属性,输入型参数,一般传nullptr。
  3. void *(*start_routine) (void *)函数指针,输入型参数。函数返回值为void*,函数参数类型为void*。线程以该函数为入口
  4. void *arg:传给回调函数start_routine的参数。
  5. 返回值,On success, pthread_create() returns 0; on error, it returns an error number(正整数),

3.3 线程退出

  • 从线程的入口函数return,就是线程退出。推荐。exit,就变成了进程退出。
  • void pthread_exit(void *retval);。线程退出。
  • int pthread_cancel(pthread_t thread);指定一个线程退出。返回值,On success, pthread_cancel() returns 0; on error, it returns a nonzero error number(正整数).
  • 线程的退出状态没有异常的概念,因为遇到异常,整个进程都退出了,由进程的退出状态判断。

3.4 线程等待

  • 当一个线程结束时,需要等待(即回收)该线程。不然会变成僵尸线程。
  • int pthread_join(pthread_t thread, void **retval);
  1. pthread_t thread线程id,输入型参数。
  2. void **retval线程的退出状态,输出型参数。如果该线程被pthread_cancel(自己cancel,也返回(void*)-1)了,进程的退出状态为(void*)-1(即宏PTHREAD_CANCELD)。
  3. 返回值,On success, pthread_join() returns 0; on error, it returns an error number(正整数).

3.5 线程分离

  • 进程默认是需要等待的(joinable),如果一个线程结束时,不想等待(即回收)该线程,想让该线程自动回收,就要设置为分离状态(!joinable or detach)。
  • int pthread_detach(pthread_t thread);
  • 一般用于主线程分离新创建的线程,或新线程自己分离自己pthread_detach(pthread_self());
  • 画外音:主线程如果pthread_detach(pthread_self());,分离自己,当退出时,进程退出,系统试图去自动回收一个正在执行进程退出流程线程。这个线程的上下文正在被使用,却又要被清理。这就像一边拆房子一边还在房子里开会一样。最终,这通常会导致一个段错误(Segmentation Fault) 或其他形式的崩溃。主线程的生命周期与进程绑定它的退出由进程退出流程自动管理,不需要也不应该手动设置其分离状态。
  • 返回值,On success, pthread_detach() returns 0; on error, it returns an error number(正整数).

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云原生俱乐部-RH294知识点归纳(3)

其实ansible还剩下使用角色和ansible内容集合来简化playbook、对ansible进行故障排除和自动执行Linux管理任务三部分。至于如何对ansible进行故障排除,只有在生产中碰到了故障才用得上,并且即使碰上的还是需要具体问题具体分析,但是可以该部分…

Flink 实时加购数据“维表补全”实战:从 Kafka 到 HBase 再到 Redis 的完整链路

一、业务背景 在电商实时运营场景中,加购行为(AddShoppingCart) 是最核心的用户行为之一,每秒钟可能产生数万条加购事件。以某头部电商平台为例,大促期间加购QPS可突破50万。 为了支持实时推荐、实时营销、实时大屏等业…

【数据结构】二叉树的顺序存储、堆的实现及其应用:堆排序与Top-K问题

二叉树的顺序存储、堆的实现及其应用:堆排序与Top-K问题 ✨前言:在上一节【树与二叉树】中,我们已经了解了二叉树的基本结构与存储方式。 本篇文章将更进一步,重点介绍 二叉树的顺序结构,并在此基础上引出一个重要的数…

SpringBoot 快速上手:从环境搭建到 HelloWorld 实战

在 Java 开发领域,Spring 框架占据着举足轻重的地位,但它复杂的配置曾让不少开发者望而却步。SpringBoot 的出现,如同为 Spring 框架装上了 “加速器”,以 “约定大于配置” 的理念简化了开发流程。本文将从环境准备、Maven 配置入…

一键部署开源 Coze Studio

文章目录一、简介1、什么是 Coze Studio2、参考地址二、安装部署1、安装docker2、安装git3、下载core4、配置公网可用5、登录成功一、简介 1、什么是 Coze Studio Coze Studio 是一站式 AI Agent 开发工具。提供各类最新大模型和工具、多种开发模式和框架,从开发到…

墨刀原型设计工具操作使用指南及实践操作

壹、墨刀原型设计工具操作使用指南 一、基础入门 1. 软件版本与环境要求 版本区别: 免费版:支持 3 个项目,单项目最多 20 页,基础组件与交互,团队成员≤5 人;专业版(付费)&#x…

博士招生 | 美国圣地亚哥州立大学 Yifan Zhang 课题组博士招生,AI 安全领域顶尖平台等你加入!

内容源自“图灵学术博研社”gongzhonghao学校简介圣地亚哥州立大学(San Diego State University, SDSU)是美国加州南部久负盛名的公立研究型大学。学校坐落于科技产业高度活跃的南加州地区,与本地软件、电信、生物科技、国防及清洁能源等领域…

用vscode使用git工具

基础用法步骤一:打开vscode的git可视化工具步骤二:点击初始化仓库步骤三:选择要加入缓存区的文件注意:这里你可以选择自己想要的文件进行添加。如果想取消缓存区的文件,这里也可以进行取消提交。步骤四:提交…

portswigger labs XXE漏洞利用实战

lab1 利用外部实体注入获取文件解决此 lab 需要读取到/etc/passwd<!DOCTYPE test [ <!ENTITY cmd SYSTEM "file:///etc/passwd"> ]> <productId>&cmd;</productId>lab2 利用 XXE 执行 SSRF 攻击通过构造 xxe 请求特定的 url 获取目录拼接…

MySQL表的操作

1.创建表创建表的语法操作&#xff1a;CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype) character set 字符集 collate 校验规则 engine 存储引擎;说明&#xff1a;field 表示列名datatype 表示列的数据类型character set 指定字符集&#xff0c;若…

第2章 cmd命令基础:证书操作(certutil)

Hi~ 我是李小咖&#xff0c;主要从事网络安全技术开发和研究。 本文取自《李小咖网安技术库》&#xff0c;欢迎一起交流学习&#x1fae1;&#xff1a;https://imbyter.com Certutil是一个Windows操作系统自带的命令行工具&#xff0c;主要用于执行各种与数字证书相关的任务&am…

LeetCode100-53最大子数组和

本文基于各个大佬的文章 上点关注下点赞&#xff0c;明天一定更灿烂&#xff01; 前言 Python基础好像会了又好像没会&#xff0c;所有我直接开始刷leetcode一边抄样例代码一边学习吧。本系列文章用来记录学习中的思考&#xff0c;写给自己看的&#xff0c;也欢迎大家在评论区指…