在编写多线程程序时,多个线程常常需要共享数据或资源。就像一家人共用一个衣柜,衣服叠好、分类放好才能避免翻乱。如果谁想拿就拉开抽屉,结果可能就是袜子乱飞、衬衫皱成一团。线程之间也一样,没有规矩就会出乱子,这时候就需要“同步”来协调。
互斥锁(Mutex)
互斥锁就像是给共享资源加了一把锁。同一时间只能有一个线程持有这把锁,处理完之后才释放。比如两个人都想用厨房做饭,但灶台只能一个人用,拿到“灶台使用权”的人才能开火。
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock);
// 操作共享资源
pthread_mutex_unlock(&lock);
信号量(Semaphore)
信号量像是管理停车位的系统。假设停车场有3个空位,信号量初始值就是3。每进一辆车减1,出来一辆加1。当值为0时,其他线程就得等着。它不只限于“有或无”,还能控制多个资源的并发访问。
#include <semaphore.h>
sem_t sem;
sem_init(&sem, 0, 3); // 允许最多3个线程进入
sem_wait(&sem);
// 访问资源
sem_post(&sem);
条件变量(Condition Variable)
有时候线程不能光靠抢锁,还得等某个条件成立。比如你等快递,不能一直开门看,而是等快递员打电话通知你。条件变量就是用来“等待 + 通知”的机制,常配合互斥锁使用。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 等待方
pthread_mutex_lock(&mutex);
while (data_ready == 0) {
pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);
// 通知方
pthread_mutex_lock(&mutex);
data_ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
自旋锁(Spinlock)
自旋锁有点像你站在微波炉前盯着转盘,不停地问“好了没”。它不会让线程睡眠,而是持续检查锁是否可用。适用于等待时间非常短的场景,省去了线程切换的开销,但会浪费CPU时间。
while (__sync_lock_test_and_set(&lock, 1)) {
// 空循环,等待
}
// 进入临界区
__sync_lock_release(&lock);
读写锁(Read-Write Lock)
读写锁区分“读”和“写”操作。就像图书馆的书,很多人可以同时阅读同一本书,但只要有人想修改,就得清场。读锁可被多个线程共享,写锁则是独占的。
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// 读线程
pthread_rwlock_rdlock(&rwlock);
// 读取数据
pthread_rwlock_unlock(&rwlock);
// 写线程
pthread_rwlock_wrlock(&rwlock);
// 修改数据
pthread_rwlock_unlock(&rwlock);