一.互斥锁
互斥锁(Mutex,即Mutual Exclusion Lock)是并发编程中用于保护 “共享资源”的同步工具,
本质是一把 “独占钥匙”;
1.当多个线程同时读写共享资源时,会出现 “竞态条件”,导致数据错误;
2.互斥锁能强制线程 “排队访问” 资源,避免竞争;
核心作用:保证 “同一时刻,只有一个线程能持有锁并访问共享资源”,实现 “互斥访问”;
#include <pthread.h>
1.pthread_mutex_init函数
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
动态初始化互斥锁
mutex 指定要进行初始化的互斥锁变量
attr 设置互斥锁的属性,若传NULL使用系统默认属性
pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER; --- 静态初始化互斥锁
成功:返回0 失败:返回非0错误码
2.pthread_mutex_lock函数
int pthread_mutex_lock(pthread_mutex_t *mutex);
用于获取互斥锁;
当互斥锁已被其他线程获取时,调用该函数的线程会被阻塞,直到互斥锁可用并成功获取;
mutex 互斥锁
成功:返回0 失败:返回非0错误码
3.pthread_mutex_trylock函数
int pthread_mutex_trylock(pthread_mutex_t *mutex);
用于获取互斥锁;
当互斥锁已被其他线程获取时,调用该函数的线程不会被阻塞,而是立即返回错误;
mutex 互斥锁
成功:返回0 失败:返回非0错误码
4.pthread_mutex_unlock函数
int pthread_mutex_unlock(pthread_mutex_t *mutex);
解锁
一般使用时,只有加锁的线程可以解锁
mutex 互斥锁
返回值 成功:返回0 失败:返回非0错误码
5.pthread_mutex_destroy函数
int pthread_mutex_destroy(pthread_mutex_t *mutex);
销毁互斥锁
mutex 互斥锁
返回值 成功:返回0 失败:返回非0错误码
二.条件变量(cond)
条件变量是并发编程中用于实现线程间“等待-通知”机制的同步工具,
可让线程在某个条件不满足时挂起, 待条件满足后被唤醒;
1.仅用互斥锁能保证共享资源访问的互斥性,但无法解决 “线程需等待特定条件成立才能继续执行” 的 场景(比如生产者 - 消费者模型中,消费者需等待生产者生产出数据才能消费);
2.条件变量可结合互斥锁,让线程在条件不满足时主动释放锁并等待,条件满足时被唤醒以重新获取锁继续执行,灵活应对依赖条件的同步需求;
核心作用:实现线程间的 “条件等待与通知”,使线程能在特定条件下协作,避免线程忙等情况消耗 CPU 资源,提升并发效率;
1.pthread_cond_init函数
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
动态初始化条件变量
cond 用于指定要初始化的条件变量
attr 设置条件变量的属性,若为NULL则使用系统默认属性
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; --- 静态初始化条件变量
成功:返回0 失败:返回非0错误码
2.pthread_cond_signal函数
int pthread_cond_signal(pthread_cond_t *cond);
唤醒至少一个等待在指定条件变量(cond)上的线程
cond 指定要操作的条件变量
成功:返回0 失败:返回非0错误码
3.pthread_cond_broadcast函数
int pthread_cond_broadcast(pthread_cond_t *cond);
唤醒所有等待在指定条件变量(cond)上的线程
cond 指定要操作的条件变量
成功:返回0 失败:返回非0错误码
4.pthread_cond_wait函数
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
线程阻塞在条件变量cond上,等待被唤醒;
同时,该函数会自动释放传入的互斥锁mutex,当线程被唤醒时,又会自动重新获取该互斥锁;
保证了线程在等待条件过程中互斥锁的正确管道,避免死锁等问题;
cond 用于指定线程等待的条件变量
mutex 与条件变量配合使用,保证线程在等待条件时的互斥
成功:返回0 失败:返回非0错误码
5.pthread_cond_destroy函数
int pthread_cond_destroy(pthread_cond_t *cond);
销毁条件变量相关的资源
cond 要销毁的条件变量
成功:返回0 失败:返回非0错误码
三.无名信号量
无名信号量是一种用于线程同步或进程同步的工具,通过维护一个计数值来控制对共享资源的访问,可限制同时访问资源的线程或进程数量;
1. 互斥锁只能保证同一时刻一个线程访问资源,而有些场景需要允许多个线程同时访问;
2. 无名信号量的计数值可灵活设置,能实现 “多线程有限并发访问” 或 “线程间的计数同步”,补充互斥锁在多资源并发场景的不足;
核心作用:
通过计数值控制共享资源的并发访问数量,
支持多线程在一定限制下同时访问资源,或实现线程间基于计数的同步协作;
#include <semaphore.h>
1.sem_init函数
int sem_init(sem_t *sem,int pshared,unsigned int value);
初始化无名信号量
sem 要初始化的信号量
pshared:
pshared = 0:信号量用于进程内的线程间同步(多个线程共享进程内存,信号量仅在当前进程内有效)
pshared != 0:信号量用于进程间同步(需将信号量放在共享内存中,被多个进程映射后共同访问)
value: 信号量的初始计数,表示可用资源的初始数量
value = 1:初始时,有 1 个 “资源” 可用,可用于实现互斥(一次一个线程/进程获取)
value = 0:初始时,没有“资源”可用,调用 sem_wait 的线程/进程会阻塞,直到sem_post增加计数
成功:返回0 失败:返回-1,重置错误码
2.sem_wait函数(P操作)
int sem_wait(sem_t *sem);
信号量的值减1
如果信号量的当前值大于 0,减 1 后函数直接返回(表示“获取资源成功”)
如果信号量的当前值等于 0,sem_wait 会阻塞,直到有其他线程/进程调用sem_post函数,使得信号量值大于0后, 再执行“减 1”并返回
sem 无名信号量
成功:返回0 失败:返回-1,重置错误码(不会改变信号量的值)
3.sem_post函数(V操作)
int sem_post(sem_t *sem);
释放信号量(将信号量的值+1)
sem 用于指定对哪个信号量进行释放操作
成功:返回0 失败:返回-1,重置错误码(不会改变信号量的值)
4.sem_destroy函数
int sem_destroy(sem_t *sem);
销毁无名信号量,释放该信号量相关的资源
sem 指定对哪个信号量进行销毁操作
成功:返回0 失败:返回-1,重置错误码
sem_getvalue (获取信号量当前值)
四.线程的互斥与同步应用场景
一.互斥锁
1.应用场景特点
单一共享资源,同一时刻只允许一个线程访问;主要用于防止数据竞争和不一致性问题
2.优势
实现简单,易于理解和使用; 能有效解决单一资源的互斥访问问题, 保障数据的一致性和完整性
3.局限性
如果线程长时间持有锁,可能导致其他线程长时间等待,降低系统并发性能;
若使用不当,容易产生死锁问题,比如多个线程循环等待对方持有的锁
二.条件变量
1.应用场景特点
线程需要在某个条件满足时才能继续执行;配合互斥锁,实现线程间的等待-通知机制
2.优势
避免线程的忙等待,有效节省CPU资源, 提高程序的运行效率;
可以实现更灵活的线程同步逻辑,满足 复杂的条件等待和协作需求。
3.局限性
必须与互斥锁配合使用,条件的判断和通知的时机需要准确把握,
否则可能导致线程无法正确唤醒或错过唤醒,影响程序的正确性
三.无名信号量
1.应用场景特点
限制对共享资源的并发访问数量; 可用于线程或进程的同步和计数控制
2.优势
可以灵活控制并发访问的资源数量, 适用于需要对资源进行定量管理的场景;
不仅能实现互斥,还能进行计数同步, 功能比互斥锁更丰富
3.局限性
信号量的计数管理需要准确设置和维护, 容易出现资源过度使用或浪费的情况;