一、线程基础核心概念

1. Linux 线程本质(内核视角)

  1. Linux 内核没有独立的线程数据结构,线程的本质是轻量级进程(Lightweight Process,LWP)
  2. 每个线程对应一个task_struct(任务控制块),内核以 LWP 为最小调度单元。
  3. 资源共享:同一进程内的多个线程共享进程地址空间 mm_struct、文件描述符表 files_struct、信号处理表 signal_struct
  4. 与普通进程的区别:
    • 普通进程: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 线程实现)

  1. Linux 使用libpthread.so线程库,完全遵循 POSIX 标准,跨平台兼容。
  2. 编码要求:
    • 头文件:#include <pthread.h>
    • 编译必须链接线程库:gcc 源码.c -o 程序 -lpthread(否则报 “未定义引用”)
  3. 调用方式:用户态通过 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
无名信号量 计数控制,可互斥可同步 多资源并发、线程执行顺序控制 灵活,支持多线程同时访问

五、线程关键注意事项

  1. 线程共享进程资源,一个线程崩溃,整个进程退出
  2. 线程退出用pthread_exit,main 函数 return 会终止所有线程。
  3. 结合态线程必须pthread_join回收,否则产生僵尸线程。
  4. 互斥锁加锁后必须解锁,条件变量必须配合互斥锁使用。
  5. 编译线程代码必须加 - lpthread链接线程库。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐