多任务并发-线程
线程(操作系统任务调度的最小单位)
什么是线程?
线程是轻量化的进程,用来实现多任务并发
线程是操作系统任务调度的最小单位
线程由进程创建,在创建时会在栈区为线程分配独立的栈区空间(默认8M)
在同一个进程中的线程共用堆区、数据区、文本区

进程线程的区别
| 进程 | 线程 |
|---|---|
| 正在执行的程序 | 轻量级的进程 |
| 操作系统资源分配的最小单位 | 操作系统任务调度的最小单位 |
| 资源空间消耗大(0-4G) | 资源空间消耗小(8M的栈区,其他区域共享) |
| 进程(创建、任务切换)效率低 | 线程(创建、任务切换)效率高 |
| 进程安全性高(空间独立) | 线程的安全性较低(有共享空间) |
| 进程间通信较为复杂、需要用到IPC机制 | 线程间通信简单(共享内存) |
| 在相同资源平台下,多进程的并发量少于多线程 |
线程相关接口
<span style="background-color:#f8f8f8"><span style="color:#333333">#include <pthread.h>
// 1. 线程的创建
// 参数: (线程ID指针, 线程属性, 线程函数入口, 传给线程函数的参数)
// 返回值: 成功返回0, 失败返回错误码(非零)
pthread_create(&tid, NULL, thread_func, (void*)arg);
// 2. 线程的退出
// 参数: 线程的返回值(可由其他线程通过pthread_join接收)
// 作用: 终止调用该函数的线程, 并返回retval给等待者
pthread_exit(void *retval);
// 3. 获取当前线程自身的ID (您留空的部分)
// 返回值: 调用该函数的线程的线程ID (pthread_t类型)
pthread_t pthread_self(void);
// 4. 等待线程结束 (线程回收)
// 参数: (要等待的线程ID, 接收线程返回值的指针)
// 返回值: 成功返回0, 失败返回错误码
// 作用: 阻塞调用线程, 直到目标线程终止, 并回收其资源
pthread_join(pthread_t thread, void **retval);</span></span>
注意:链接的时候必须显式链接 -lpthread
线程的分离属性
分离属性:不需要回收的线程,称为具有分离属性的线程,结束时可以被操作系统回收。
非分离属性:可以被其他线程回收或者结束的线程成为非分离属性的线程。(默认的属性)
线程的互斥
互斥锁 - 保护共享资源,防止并发访问冲突
<span style="background-color:#f8f8f8"><span style="color:#333333">pthread_mutex_init() // 初始化
pthread_mutex_lock() // 加锁(阻塞)
pthread_mutex_trylock() // 加锁(非阻塞)
pthread_mutex_unlock() // 解锁
pthread_mutex_destroy() // 销毁</span></span>
条件变量 - 等待某个条件成立(必须配合互斥锁)
条件变量就是为了避免CPU空转轮询而设计的,让线程在条件不满足时安心"睡觉",条件满足时被"叫醒"
<span style="background-color:#f8f8f8"><span style="color:#333333">pthread_cond_init() // 初始化
pthread_cond_wait() // 等待条件(自动释放锁)
pthread_cond_timedwait() // 限时等待
pthread_cond_signal() // 唤醒一个等待线程
pthread_cond_broadcast() // 唤醒所有等待线程
pthread_cond_destroy() // 销毁</span></span>
线程间的同步机制
信号量 - 管理资源数量(独立使用,无需互斥锁)
<span style="background-color:#f8f8f8"><span style="color:#333333">sem_init() // 初始化(初始资源数)
sem_wait() // P操作:资源数-1(为0则阻塞)
sem_trywait() // 非阻塞版
sem_timedwait() // 限时版
sem_post() // V操作:资源数+1(唤醒等待者)
sem_getvalue() // 获取当前计数
sem_destroy() // 销毁</span></span>
死锁的产生条件
死锁是指两个或多个线程(进程)互相等待对方持有的资源,导致所有线程都无法继续执行。
四个必要条件(必须同时满足)
| 条件 | 说明 | 比喻 |
|---|---|---|
|
1. 互斥 (Mutual Exclusion) | 资源一次只能被一个线程占用 | 厕所只有一间,一次只能进一个人 |
|
2. 持有并等待 (Hold and Wait) | 线程持有资源的同时,等待其他资源 | 你占着厕所A,还等着厕所B空出来 |
|
3. 不可抢占 (No Preemption) | 已分配的资源不能被强制剥夺 | 别人不能把你从厕所里拽出来 |
|
4. 循环等待 (Circular Wait) | 线程间形成循环等待链 | A等B,B等C,C等A,都在等对方让出资源 |
只要破坏任意一个条件,死锁就不会发生!
如何避免死锁(5种策略)
-
破坏"循环等待":统一加锁顺序(最常用)
-
破坏"持有并等待":一次性申请所有资源
-
破坏"不可抢占":使用 trylock + 回退
-
使用递归锁
-
使用更高层级的同步机制
-
信号量:管理资源计数,自然避免死锁
-
条件变量:配合互斥锁使用,但设计合理可避免死锁
-
读写锁:允许多个读操作并发
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)