当前位置: 首页 > news >正文

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.dtcms.com/a/348438.html

相关文章:

  • 高并发内存池(1)-定长内存池
  • 阿里开源通义万相Wan2.2:视频生成技术的革命性突破
  • MR椎间盘和腰椎分割项目:基于深度学习的医学图像分析
  • Linux系统之Centos7安装cockpit图形管理界面
  • 项目学习总结(5)
  • python---构造函数、析构函数
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘gunicorn’问题
  • 【springboot 技术代码】集成mongodb 详细步骤
  • localhost和127.0.0.1的区别
  • 界面规范7-可左右拖动的分割条
  • MATLAB GUI 设计入门:用 Guide 工具快速搭建交互界面
  • React Hooks useEffect的使用
  • React 18+ 并发模式异常
  • Linux服务测试题(DNS,NFS,DHCP,HTTP)
  • pytorch线性回归(二)
  • ⭐CVPR2025 病理分析全能模型 CPath-Omni 横空出世
  • RAG智能问答为什么需要进行Rerank?
  • 春秋云镜 Flarum
  • UCIE Specification详解(二)
  • Linux学习-TCP网络协议
  • 基于springboot的高校后勤保修服务系统/基于android的高校后勤保修服务系统app
  • openFeign用的什么协议,dubbo用的什么协议
  • 【重学MySQL】八十七. 触发器管理全攻略:SHOW TRIGGERS与DROP TRIGGER实战详解
  • k8s下的网络通信之calico与调度
  • MySQL官方C/C++ 接口入门
  • 从栈到堆:深入理解C语言静态与动态链表的创建与管理
  • 利旧小天才儿童电话手表实现“一键寻车”功能
  • 线程整理文档
  • 使用UE5开发《红色警戒3》类战略养成游戏的硬件配置指南
  • 【Spring Cloud 微服务】3.智能路由器——深入理解与配置负载均衡