linux——线程

线程概念

什么是线程?

  • 在一个程序里的一个执行流叫做线程。
  • 一切进程至少有一个线程
  • 线程在进程内部运行,本质是在进程地址空间内运行
  • 在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化

我们都知道在每一个进程都有属于自己的PCB,里面装满了

描述进程的各种字段...,而线程呢,是在进程中产生的,所以会共享共一个进程地址空间,如上图所示。

线程的优点

  • 创建一个新线程的代价要比创建一个新进程小
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要小很多
  • 线程占比的资源比进程小很多、
  • 能充分利用多处理器的可并行数量
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务

线程的缺点

  • 性能的损失
    • 一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的
      同步和调度开销,而可用的资源不变。
  • 健壮性差: 编写多线程的时候,很多时候线程是不安全的

进程和线程的差别

  • 进程是资源分配的基本单位,站在内核的角度来讲,进程就是承担分配系统资源的基本实体
  • 线程是调度的基本单位
  • 线程共享进程数据,但也有自己的一部分数据
    • 线程ID
    • 一组寄存器:保存属于自己的上下文
    • 栈(这很重要)
    • errno
    • 信号屏蔽字等等

以下我将聊一聊POSIX线程库

  • 与线程相关的函数构成了一个完整的系列,绝大多都是"pthread_"打头
  • 所以要用这些函数需要引用<pthraed.h>头文件
  • 链接的时候需要加上-lpthread

在我们链接线程库的时候,我们需要将线程库给加载进自己的地址空间中(共享区),然后当我们需要什么函数的时候,直接去共享区去取。

创建线程

第一个参数(thread):线程的ID

第二个参数(attr):线程的属性

第三个参数(start_routine):是个函数地址,线程启动的时候执行的函数

第四个参数(arg):传给线程启动函数的参数

返回值:失败返回0,否则返回错误码,错误码被设置了

关于线程ID

其实真实的线程ID是下图所示

pthread_t是什么类型呢? 我们可以理解为是进程地址空间的一个地址。

前面讲过,当程序运行的时候,会将线程库给放进共享区中,所以这个线程ID就是共享区中的一个地址。 而这个地址其实就是线程控制块的地址,里面存放着线程独有的数据

你看PID一样,但是LWP是不一样的,这样证明了我上述的结论。

cpp 复制代码
5 void* routine(void *args)
  6 {
  7     int i;
  8     for(;;)
  9     {
 10         std::cout << "I am thread" <<std::endl;
 11         sleep(1);
 12     }
 13 }
 14 
 15 int main()
 16 {
 17     pthread_t tid;
 18     int ret;
 19     if(ret == pthread_create(&tid,nullptr,&routine,nullptr) != 0)
 20     {
 21         std::cout << "pthread_create err" << std::endl;
 22         exit(-1);
 23     }
 24 
 25     int i;
 26     for(;;)
 27     {
 28         std::cout << "I am main thread" <<std::endl;
 29         sleep(1);                                                                                                                                                    
 30     }
 31 
 32     return 0;
 33 }

线程退出

参数 value_ptr: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参数。
相关推荐
invicinble4 小时前
这里对java的知识体系做一个全域的介绍
java·开发语言·python
wbs_scy4 小时前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·开发语言
ss2735 小时前
食谱推荐系统功能测试如何写?
java·数据库·spring boot·功能测试
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题】【Java基础篇】第15题:JDK1.7中HashMap扩容为什么会发生死循环?如何解决
java·开发语言·数据结构·后端·面试·哈希算法
倔强的石头1065 小时前
【Linux指南】基础IO系列(八):实战衔接 —— 给微型 Shell 添加完整重定向功能
linux·运维·服务器
try2find5 小时前
打印ascii码报错问题
java·linux·前端
014-code5 小时前
CompletableFuture 实战模板(超时、组合、异常链处理)
java·数据库
Nicander5 小时前
多数据源下@transcation事务踩坑
java·后端
Ujimatsu6 小时前
虚拟机安装Ubuntu 26.04.x及其常用软件(2026.4)
linux·运维·ubuntu
それども6 小时前
DELETE 和 TRUNCATE TABLE区别
java·数据库·mysql