Linux线程
·
一、线程基础核心概念
1. Linux 线程本质(内核视角)
- Linux 内核没有独立的线程数据结构,线程的本质是轻量级进程(Lightweight Process,LWP)。
- 每个线程对应一个task_struct(任务控制块),内核以 LWP 为最小调度单元。
- 资源共享:同一进程内的多个线程共享进程地址空间 mm_struct、文件描述符表 files_struct、信号处理表 signal_struct。
- 与普通进程的区别:
- 普通进程:task_struct 对应独立的 mm_struct(独立地址空间)。
- 线程:task_struct共享同一 mm_struct,是同一地址空间下的多个调度单元。
2. 线程状态
线程作为 LWP,状态与 Linux 进程状态相同:
| 状态标识 | 状态名称 | 含义 |
|---|---|---|
| R | 运行 / 就绪态 | 正在 CPU 执行 或 等待 CPU 调度 |
| S | 可中断睡眠态 | 等待事件 / I/O,可被信号唤醒 |
| D | 不可中断睡眠态 | 等待关键硬件操作,不可被中断 |
| T | 停止态 | 被 SIGSTOP 暂停,可被 SIGCONT 恢复 |
| Z | 僵尸态 | 线程终止,资源未被回收 |
| X | 死亡态 | 资源完全释放,瞬间不可观测 |
3. POSIX 线程标准(Linux 线程实现)
- Linux 使用libpthread.so线程库,完全遵循 POSIX 标准,跨平台兼容。
- 编码要求:
- 头文件:
#include <pthread.h> - 编译必须链接线程库:
gcc 源码.c -o 程序 -lpthread(否则报 “未定义引用”)
- 头文件:
- 调用方式:用户态通过 POSIX 接口操作线程,不直接调用内核系统调用。
4. 进程 vs 线程(核心区别)
| 对比维度 | 进程(Process) | 线程(Thread/LWP) |
|---|---|---|
| 调度单位 | 资源分配 + 调度的基本单位 | 内核最小调度单元 |
| 资源 | 独立地址空间、文件描述符、信号表 | 共享所属进程的所有资源,仅独立栈 / 程序计数器 |
| 创建 / 销毁开销 | 大(需分配 / 回收全部资源) | 小(仅分配调度相关资源) |
| 通信方式 | 需 IPC(管道 / 消息队列 / 共享内存) | 直接读写全局变量,通信极简 |
| 稳定性 | 一个进程崩溃不影响其他进程 | 一个线程崩溃,整个进程退出 |
| 适用场景 | 独立任务、第三方代码、需隔离的服务 | 多核并行、高频数据共享、协作子任务 |
二、线程核心函数
所有线程函数成功返回 0,失败返回非 0 错误码,无 errno。
1. 线程创建:pthread_create
#include <pthread.h>
int pthread_create(
pthread_t *thread, // 输出:存储新线程ID
const pthread_attr_t *attr, // 线程属性,NULL=默认
void *(*start_routine)(void *), // 线程入口函数
void *arg // 传给入口函数的参数
);
- 功能:在当前进程中创建一个新线程。
- 注意:入口函数格式固定为
void* func(void*),无参数则 arg 传 NULL。
2. 线程退出:pthread_exit
#include <pthread.h>
void pthread_exit(void *retval); // 无返回值
- 功能:仅终止当前线程,不影响进程内其他线程。
- 参数:retval 为线程退出状态值,可被
pthread_join接收。 - 关键:main 函数 return 会终止整个进程,线程退出必须用
pthread_exit。
3. 获取线程 ID:pthread_self
#include <pthread.h>
pthread_t pthread_self(void);
- 功能:获取当前线程的线程 ID。
- 特点:总是调用成功,直接返回线程 ID。
4. 线程资源回收:pthread_join
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
- 功能:阻塞等待指定线程结束,并回收其资源。
- 参数:
- thread:要回收的线程 ID
- retval:接收线程退出状态,不关心传 NULL
- 注意:只能回收结合态线程,分离态线程调用会失败。
5. 线程分离 / 结合态设置
(1)结合态 vs 分离态
| 对比维度 | 结合态(JOINABLE,默认) | 分离态(DETACHED) |
|---|---|---|
| 资源回收 | 必须用pthread_join手动回收 |
线程终止后系统自动回收 |
| pthread_join | 有效,阻塞等待 | 无效,调用返回错误 |
| 僵尸风险 | 未回收会产生僵尸线程 | 无僵尸线程 |
| 设置方式 | 默认 / 属性设置 | 创建时属性设置 /pthread_detach |
| 适用场景 | 需要获取线程退出状态 | 无需状态,自动释放 |
(2)线程属性操作函数
// 初始化线程属性
int pthread_attr_init(pthread_attr_t *attr);
// 设置分离状态
int pthread_attr_setdetachstate(
pthread_attr_t *attr,
int detachstate // PTHREAD_CREATE_JOINABLE/DETACHED
);
// 销毁线程属性
int pthread_attr_destroy(pthread_attr_t *attr);
(3)将线程设为分离态:pthread_detach
#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:将已创建的结合态线程标记为分离态。
6. 线程取消相关函数
(1)发送取消请求:pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:向指定线程发送取消请求,是否取消由目标线程决定。
(2)设置线程可取消状态
int pthread_setcancelstate(int state, int *oldstate);
state:
PTHREAD_CANCEL_ENABLE:可被取消(默认)PTHREAD_CANCEL_DISABLE:不可被取消
(3)设置线程取消类型
int pthread_setcanceltype(int type, int *oldtype);
type:
PTHREAD_CANCEL_DEFERRED:延时取消(默认),到取消点才取消PTHREAD_CANCEL_ASYNCHRONOUS:立即取消
三、线程互斥与同步
线程共享进程资源,并发访问共享数据会产生竞态条件,需用同步工具保证安全。
1. 互斥锁(Mutex)
核心作用
解决共享资源互斥访问,保证同一时刻只有一个线程持有锁并操作资源,避免数据竞争。
核心函数
#include <pthread.h>
// 1. 动态初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
// 静态初始化:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 2. 加锁(阻塞)
int pthread_mutex_lock(pthread_mutex_t *mutex);
// 3. 尝试加锁(非阻塞)
int pthread_mutex_trylock(pthread_mutex_t *mutex);
// 4. 解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// 5. 销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
使用规范
加锁 → 操作共享资源 → 解锁,加锁和解锁必须成对出现,防止死锁。
2. 条件变量
核心作用
实现线程等待 - 通知机制,解决 “线程需等待条件成立才能执行” 的场景,避免忙等浪费 CPU。
- 必须与互斥锁配合使用。
核心函数
#include <pthread.h>
// 1. 动态初始化条件变量
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
// 静态初始化:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 2. 等待条件满足(阻塞)
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
// 关键:自动释放互斥锁 → 等待唤醒 → 唤醒后自动重新获取锁
// 3. 唤醒一个等待线程
int pthread_cond_signal(pthread_cond_t *cond);
// 4. 唤醒所有等待线程
int pthread_cond_broadcast(pthread_cond_t *cond);
// 5. 销毁条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
典型场景
生产者 - 消费者模型:消费者等待数据,生产者生产后唤醒消费者。
3. 无名信号量
核心作用
通过计数值控制共享资源的并发访问数量,可实现互斥(值 = 1)或同步(值 = 0),支持线程 / 进程间同步。
核心函数
#include <semaphore.h>
// 1. 初始化无名信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
// pshared=0:线程间同步;pshared≠0:进程间同步
// value:初始计数值(1=互斥,0=同步)
// 2. P操作(申请资源:值-1,为0则阻塞)
int sem_wait(sem_t *sem);
// 3. V操作(释放资源:值+1,唤醒等待线程)
int sem_post(sem_t *sem);
// 4. 销毁信号量
int sem_destroy(sem_t *sem);
四、线程同步工具对比
| 工具 | 核心能力 | 适用场景 | 特点 |
|---|---|---|---|
| 互斥锁 | 独占资源,互斥访问 | 单一共享数据保护(如全局变量、链表) | 实现简单,易死锁,只能单线程访问 |
| 条件变量 | 等待 - 通知,无忙等 | 线程依赖条件执行(生产者 - 消费者) | 必须配互斥锁,节省 CPU |
| 无名信号量 | 计数控制,可互斥可同步 | 多资源并发、线程执行顺序控制 | 灵活,支持多线程同时访问 |
五、线程关键注意事项
- 线程共享进程资源,一个线程崩溃,整个进程退出。
- 线程退出用
pthread_exit,main 函数 return 会终止所有线程。 - 结合态线程必须
pthread_join回收,否则产生僵尸线程。 - 互斥锁加锁后必须解锁,条件变量必须配合互斥锁使用。
- 编译线程代码必须加 - lpthread链接线程库。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)