线程同步与互斥核心要点整理

线程同步与互斥核心要点整理
一、同步与互斥基础
-
核心问题:
- 数据竞争:多线程共享资源(全局变量、文件、数据库)时,CPU时间片轮询可能导致数据错乱。
- 示例:银行账户操作中,存钱与取钱线程并发执行可能破坏余额一致性。
-
关键概念:
- 互斥:同一时间仅一个线程访问临界资源,通过互斥锁实现。
- 同步:控制线程执行顺序,通过信号量、条件变量实现。
- 临界资源:多线程共享的资源(如
int money)。 - 临界区:操作临界资源的代码段(如修改
money的代码)。
二、互斥锁(pthread_mutex_t)
-
核心函数:
函数 功能 参数说明 pthread_mutex_init()初始化锁(静态/动态) 锁指针、属性(NULL为普通锁) pthread_mutex_lock()阻塞式加锁 锁指针 pthread_mutex_trylock()非阻塞尝试加锁 锁指针 pthread_mutex_unlock()解锁 锁指针 pthread_mutex_destroy()销毁锁 锁指针 -
特性:
- 普通锁:重复加锁会导致死锁。
- 递归锁:允许同一线程多次加锁,通过属性
PTHREAD_MUTEX_RECURSIVE_NP设置。 - 代码示例:
c
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&mutex);// 临界区操作pthread_mutex_unlock(&mutex);
三、死锁与递归锁
-
常见死锁场景:
- 重复加锁:同一线程对同一锁多次加锁。
- 交叉加锁:线程A持有锁1请求锁2,线程B持有锁2请求锁1。
- 未释放锁:线程异常退出未解锁。
-
递归锁解决方案:
- 初始化递归锁:
pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);pthread_mutex_init(&mutex, &attr); - 递归锁示例:允许函数递归调用时多次加锁。
- 初始化递归锁:
四、信号量(sem_t)
-
核心函数:
函数 功能 参数说明 sem_init()初始化信号量 信号量指针、共享标志(0为线程共享)、初始值 sem_wait()P操作(信号量减1,阻塞) 信号量指针 sem_post()V操作(信号量加1) 信号量指针 sem_destroy()销毁信号量 信号量指针 -
应用场景:
- 控制并发线程数:如允许多个线程同时写入日志文件。
- 生产者-消费者模型:通过信号量协调生产与消费的节奏。
- 代码示例:
sem_t sem;sem_init(&sem, 0, 3); // 允许3个线程并发访问sem_wait(&sem); // 进入临界区sem_post(&sem); // 退出临界区
五、条件变量(pthread_cond_t)
-
核心函数:
函数 功能 参数说明 pthread_cond_init()初始化条件变量 条件变量指针、属性(通常为NULL) pthread_cond_wait()阻塞线程,释放锁并等待信号 条件变量指针、互斥锁指针 pthread_cond_signal()唤醒一个等待线程 条件变量指针 pthread_cond_broadcast()唤醒所有等待线程 条件变量指针 pthread_cond_destroy()销毁条件变量 条件变量指针 -
应用场景:
- 生产者-消费者模型:生产者生产数据后唤醒消费者。
- 解决空转问题:通过标志位(如
flag)判断是否需要等待。 - 代码示例:
pthread_cond_t cond;pthread_mutex_t mutex;int flag = 0;// 生产者pthread_mutex_lock(&mutex);flag = 1;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);// 消费者pthread_mutex_lock(&mutex);while (flag == 0) {pthread_cond_wait(&cond, &mutex);}// 消费数据pthread_mutex_unlock(&mutex);
六、线程顺序控制
- 互斥锁实现顺序控制:
- 示例:通过多把锁强制线程执行顺序(如打印ABC)。
// 线程Apthread_mutex_lock(&a);printf("A");pthread_mutex_unlock(&b);// 线程Bpthread_mutex_lock(&b);printf("B");pthread_mutex_unlock(&c);// 线程Cpthread_mutex_lock(&c);printf("C");pthread_mutex_unlock(&a);
- 示例:通过多把锁强制线程执行顺序(如打印ABC)。
七、生产者-消费者模型优化
- 最终版代码逻辑:
- 双条件变量:生产者和消费者使用不同的条件变量(
cond和cond1)。 - 共用互斥锁:通过
flag标志位和循环检查避免空转。 - 核心代码:
// 生产者pthread_mutex_lock(&mutex);while (flag != 0) pthread_cond_wait(&cond1, &mutex);flag = 1;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);// 消费者pthread_mutex_lock(&mutex);while (flag != 1) pthread_cond_wait(&cond, &mutex);flag = 0;pthread_cond_signal(&cond1);pthread_mutex_unlock(&mutex);
- 双条件变量:生产者和消费者使用不同的条件变量(
八、机制对比与最佳实践
| 机制 | 用途 | 特点 |
|---|---|---|
| 互斥锁 | 保证临界资源独占访问 | 简单高效,但无法控制顺序 |
| 信号量 | 控制并发线程数量 | 可设置资源池大小(如连接池) |
| 条件变量 | 线程间状态通知与协作 | 需配合互斥锁,解决复杂同步问题 |
最佳实践:
- 避免死锁:按固定顺序请求锁,使用超时机制(如
pthread_mutex_trylock)。 - 减少锁粒度:仅对必要代码段加锁,缩短临界区。
- 优先使用高层同步机制:条件变量适合复杂同步逻辑,信号量适合资源池控制。
