Linux系统编程 | 线程的基本概念

发布于:2025-03-29 ⋅ 阅读:(22) ⋅ 点赞:(0)

💓个人主页:mooridy
💓专栏地址:Linux
关注我🌹,和我一起学习更多计算机的知识!

🔝🔝🔝

什么是线程

程序中的一个执行路线就叫做线程

  • 一个进程至少要有一个执行线程,单个进程本身就是一个执行流,所以单个进程某种意义上也是一个线程(是主线程).线程在进程内部运行,本质是在进程地址空间内运行
  • 在Linux操作系统下,线程就是轻量化进程,线程是没有独立的地址空间的PCN结构,线程的资源是主线程共享给它们的。
    ![[Pasted image 20250325104542.png]]

线程的优点

• 线程的创建时间比进程快
因为进程在创建的过程中,还需要资源管理信息,比如内存管理信息、文件管理信息,而线程在创建的过程中,不会涉及这些资源管理信息,而是共享它们;

• 同一个进程内的线程切换比进程切换快
因为线程具有相同的地址空间(虚拟内存共享),这意味着同一个进程的线程都具有同一个页表,同一个虚拟地址空间,那么在切换的时候不需要切换页表。同时也不会扰乱处理器的缓存机制。
• 线程之间的数据交互效率更高
由于同一进程的各线程间共享内存和文件资源,那么在线程之间数据传递的时候,就不需要经过内核了;

线程异常

线程是进程的执⾏分⽀,线程出异常,就类似进程出异常,进⽽触发信号机制,会终⽌整个进程,该进程内的所有线程也就随即退出。

线程与进程的比较

进程资源分配的单位,线程CPU 调度的单位;
• 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈、线程ID、信号屏蔽字、调度优先级

进程的多个线程共享

同⼀地址空间,因此Text SegmentData Segment都是共享的,如果定义⼀个函数,在各线程中都可以调⽤,如果定义⼀个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
⽂件描述符表、每种信号的处理⽅式(SIG_ IGN、SIG_ DFL或者⾃定义的信号处理函数)、当前⼯作⽬录、用户id和组id

主线程的PID和LWP相同,CPU调度时是在看LWP,而不是PID,线程的PID和主线程相同,自己独有LWP

Linux线程控制

POSIX线程库

由于pthred是第三方库
所以编译时要加上-lpthread的字段

如何创建线程
功能:创建⼀个新的线程

原型:

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;失败返回错误码
如何终止线程
  1. 从线程函数return。这种⽅法对主线程不适⽤,从main函数return相当于调⽤exit。(大多数情况)

  2. 线程可以调⽤pthread_ exit终⽌⾃⼰。

功能:线程终⽌
原型:

 void pthread_exit(void *value_ptr);
 参数:

 value_ptr: 指向退出状态的指针,可传递任意类型数据value_ptr不要指向⼀个局部变量。
返回值:

⽆返回值,跟进程⼀样,线程结束的时候⽆法返回到它的调⽤者(⾃⾝)
  1. ⼀个线程可以调⽤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的线程终⽌。

如何进行线程分离
  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进⾏pthread_join操作,否则⽆法释放资源,从⽽造成系统泄漏。
  • 如果不关⼼线程的返回值,join是⼀种负担,这个时候,我们可以告诉系统,当线程退出时,⾃动释放线程资源。
int pthread_detach(pthread_t thread);

pthread_self()函数可以返回当前线程的线程ID,所以假设我们想要当前线程与主线程脱离关系,可以这样写: ```

pthread_detach(pthread_self());

线程ID本质

首先,pthread_create的返回值是线程ID.
线程ID的本质是一个地址,pthread库是一个动态库,是第三方库,这个库会被映射到进程的地址空间的共享区中,而线程ID所指的地址则是pthread这个库层面上,线程集合的起始地址
![[Pasted image 20250327113215.png]]

线程栈
  • 这种stack不能动态增⻓,⼀旦⽤尽就没了,这是和⽣成进程的fork不同的地⽅。
  • 对于⼦线程的 stack ,它其实是在进程的地址空间中map出来的⼀块内存区域,原则上是线程私有的,但是同⼀个进程的所有线程⽣成的时候,是会浅拷⻉⽣成者的 task_struct 的很多字段,如果愿意,其它线程也还是可以访问到的,于是⼀定要注意。

网站公告

今日签到

点亮在社区的每一天
去签到