文章目录
- 线程
-
- 一、线程的相关定义
- 二、线程的创建
- 三、进程和线程的区别
- 四、线程的调度
- 五、线程的消亡
- 六、线程相关的函数接口
-
- 6.1 创建线程
- 6.2 线程的非分离属性:
- 6.3 线程退出及资源回收
- 七、线程的同步和互斥
-
- 7.1 线程间通信
- 7.2 线程间互斥机制
- 7.3 线程间同步机制
- 八、死锁

线程
一、线程的相关定义
- 线程是一个轻量级的进程,用来实现多任务并发。
- 线程是操作系统任务调度的最小单位。
- 进程是操作系统资源分配的最小单位。
主线程:创建线程的进程。 次线程:由进程创建出来的线程。
二、线程的创建
- 线程由所在的进程创建,线程一定是属于某个进程的。
- 线程创建时,所在进程为其分配独立的栈区空间(默认8M),线程共用进程的堆区、数据区、文本区、内核区。

三、进程和线程的区别
| 概念 | 操作系统资源分配的最小单位 | CPU任务调度的最小单位 |
| 效率 | 进程要为进程分配4G的虚拟内存空间 | 线程的创建要比进程创建要块,只需要分配栈区空间即可 |
| 内存 | 消耗大(4G) | 消耗小(仅需独立的8M栈区空间,其余的与进程共享) |
| 并发量 | 相同资源环境下,并发量少 | 并发量多 |
| 安全性 | 进程间空间独立,安全性高 | 除栈区外,其余空间共用,安全性低 |
| 通信 | 进程间不能直接通信,需要使用IPC机制通信 | 线程可以直接通信(例如:全局变量、全局队列等) |
四、线程的调度
宏观并行、微观串行 调度方式与进程相同
五、线程的消亡
六、线程相关的函数接口
6.1 创建线程
pthread_create
- 函数原型:#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
- 功能
创建并启动一个线程。
- 参数
thread:保存线程ID的变量地址; attr:设置线程属性的变量地址;(NULL:按照默认属性创建) start_routine:函数指针,指向线程执行的任务函数的指针(线程任务函数); arg:传递给线程任务函数的参数。
- 返回值:
成功:返回0; 失败:返回错误码(!0)。
- 获取ID号:
pthread_self() //获取当前线程ID号
注意:
6.2 线程的非分离属性:
线程的分离属性:不需要被其他线程回收的线程,称之为具有分离属性的线程,将来执行结束,由操作系统回收。
设置tid对应的线程为分离属性的线程。 pthread_detach(tid); 使用场景:其他线程没有机会回收该线程时,可以将该线程设置成分离属性。
线程的非分离属性:可以被其他线程结束和回收的线程,称为具有非分离属性的线程。 因此,具有非分离属性的线程结束后,必须要被其他线程回收。
线程默认属性:非分离属性
6.3 线程退出及资源回收
pthread_exit
- 函数原型#include <pthread.h>
void pthread_exit(void *retval);
pthread_join
-
函数原型
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
-
功能
阻塞回收线程资源空间和状态。
-
参数
thread:要回收的线程的线程ID。 retval:保存线程退出状态变量的地址; NULL表示不接受状态。
-
返回值:
成功:返回0; 失败:返回!0。
七、线程的同步和互斥
7.1 线程间通信
位于数据区的全局变量、堆区申请的空间(队列)、pthread_create传参、条件变量。
多线程访问临界资源时,存在资源竞争问题。
- 临界资源:多个线程可以同时访问的区域(文件、数据库、内存中的全局变量等)。
- 资源竞争:多个线程同时想对一块内存进行访问。
- 临界区:访问临界资源的这段代码称为临界区。
- 解决方法:互斥机制。
7.2 线程间互斥机制
互斥机制:让多个线程访问临界资源时,具有排他性访问特性。 互斥机制的实现:互斥锁。 1. 创建一个互斥锁对象:pthread_mutex_t 2. 初始化互斥锁:pthread_mutex_init(); 3. 加锁:pthread_mutex_lock(); 4. 解锁:pthread_mutex_unlock(); 5. 销毁互斥锁:pthread_mutex_destroy()
在linux系统终端中安装互斥锁的库指令: sudo apt-get install manpages-posix manpages-posix-dev
-
pthread_mutex_init/pthread_mutex_destroy
- 函数原型:#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex); - 功能:
初始化/销毁一个锁。
- 参数:
mutex:要初始化/销毁的锁对象的地址; attr:锁属性的首地址(NULL:默认属性)。
- 返回值
成功:返回0; 失败:indicate the error.
- 函数原型:#include <pthread.h>
-
pthread_mutex_lock/pthread_mutex_unlock
- 函数原型:#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex); - 功能:
上锁/解锁。
- 参数:
mutex:锁地址。
- 函数原型:#include <pthread.h>
其他锁: 读写锁:读共享,写独占。 自旋锁:申请不到锁时,一直占用CPU。
7.3 线程间同步机制
线程间同步:让多个线程执行任务时,具有一定先后顺序。 
信号量:资源数; 1. 创建信号量对象sem_t; 2. 初始化信号量sen_init(); 3. 申请信号量(P操作)sem_wait(); 4. 释放信号量(V操作)sem_post(); 5. 销毁信号量;sem_destroy()
- sem_init
- 函数原型:#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value); - 功能:
初始化一个信号量。
- 参数:
sem:信号量对象地址; pshared:0:线程间共享使用;!0:进程间共享使用; value:信号量初始值。
- 返回值:
成功:返回0; 失败:返回!0。
- 函数原型:#include <semaphore.h>
- sem_wait
- 函数原型:#include <semaphore.h>
int sem_wait(sem_t *sem); - 功能:
申请一个信号量。
- 参数:
sem:信号量对象地址。
- 返回值:
成功:返回0; 失败:返回!0。
- 函数原型:#include <semaphore.h>
- sem_post
- 函数原型:#include <semaphore.h>
int sem_post(sem_t *sem); - 功能:
释放一个信号量。
- 参数:
sem:信号量对象地址。
- 返回值:
成功:返回0; 失败:返回!0。
- 函数原型:#include <semaphore.h>
八、死锁
死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,且互相请求对方未释放资源,从而导致陷入永久等待状态的情况。
-
现象
- 现象1:忘记释放锁
- 现象2:重复加锁
- 现象3:多线程多锁,抢占锁资源不当
如:线程A获取了1锁,线程B获取了2锁,同时线程A还想获取2锁,线程B还想获取1锁
-
产生死锁的四个必要条件
- 互斥条件:一个资源同一时刻只能被一个任务占用(一个执行流获取锁后,其它执行流不能再获取该锁)。
- 请求与保持条件:已经拿着一部分资源不释放,同时又去申请新的资源(执行流本身使用着一把锁并不释放,还在请求别的锁)。
- 不剥夺条件:资源只能由持有者主动释放,系统/其他任务不能强行抢过来(A执行流拿着锁,其它执行流不能释放)。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系(多个执行流拿着对方想要的锁,并且各执行流还去请求对方的锁)。
-
解决方法
- 锁一定要成对出现
- 使线程的加解锁顺序一致
- 破坏环路等待条件
四条全中 = 死锁,破掉任意一条 = 解除
使用非阻塞锁,一旦线程发现请求的锁被使用,就去释放自己拥有的资源
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int sem_trywait(sem_t *sem);
网硕互联帮助中心




评论前必须登录!
注册