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

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.xdnf.cn/news/18672.html

相关文章:

  • CTFshow系列——命令执行web49-52
  • 基于深度学习的眼疾识别系统:从血细胞分类到病理性近视检测
  • 计算机网络:聊天室(UDP)
  • 用户和组笔记
  • 大数据毕业设计选题推荐-基于大数据的北京市医保药品数据分析系统-Spark-Hadoop-Bigdata
  • 基于角色的访问控制(RBAC)研究与Go语言实现
  • 商超客流密度统计误差率↓35%!陌讯多模态融合算法在零售智慧运营的实战解析
  • 美股期权历史市场数据波动特性分析
  • power query自定义查询函数(中午休息一小时
  • 基于Spark的热门旅游景点数据分析系统的设计-django+spider
  • 基于springboot的理商管理平台设计与实现、java/vue/mvc
  • pom.xml 标签整理各个标签的用途和含义
  • 复杂场景鲁棒性突破!陌讯自适应融合算法在厂区越界检测的实战优化​
  • 57 C++ 现代C++编程艺术6-类的内部类
  • DBeaver连接SQL Server集成认证问题解决方案
  • 题解:P13822 「Diligent-OI R2 B」白露为霜_奇偶性_数学归纳_算法竞赛C++
  • 将C++资源管理测试框架整合到GitLab CI/CD的完整实践指南
  • ffmpeg 问答系列-> mux 部分
  • C6.1:发射极偏置放大器
  • 阿里 通义千问 Java23种设计模式
  • IDM 下载失败排查指南:全面解析与解决方案
  • 深入解析 std::enable_if:原理、用法与现代 C++ 实践
  • 编程与数学 02-017 Python 面向对象编程 20课题、迭代器模式
  • 大数据毕业设计选题推荐-基于大数据的丙型肝炎患者数据可视化分析系统-Hadoop-Spark-数据可视化-BigData
  • 深入解析十大经典排序算法原理与实现
  • 室联人形机器人:家政服务任务结构化、技术要点、深入应用FPGA的控制系统框架设计(整合版A)
  • 【运维进阶】高可用和负载均衡技术
  • Django的Serializers与 fastapi 的Pydantic
  • 【R语言】R语言中 rbind() 与 merge() 的区别详解
  • 网络编程-创建TCP协议服务器