Linux同步

67 阅读2分钟

基础知识

  1. 同步的必要性:对共享资源的竞争并发
  2. 实现同步的方法很多:互斥锁、读写锁、条件变量以及信号量等

互斥锁mutex

本质是结构体,里面有整数,也有阻塞队列等

pthread_mutex_t lock;//创建锁
pthread_mutex_init(&lock,NULL);//设置锁为1
pthread_mutex_lock(&lock);//--,如果<0则加入阻塞队列
pthread_mutex_unlock(&lock);//++,如果<=0,则从阻塞队列取出线程
pthread_mutex_destroy(&lock);//销毁锁,释放空间

读写锁rwlock

注意只有一把锁,只是加锁方式有两种,解锁方式统一

  1. 读共享
  • 多个读线程可以同时持有读锁。
  • 如果当前有写线程正在执行等待active_writers > 0 或 writers > 0),读线程需要等待。
  1. 写独占
  • 同一时间只能有一个写线程持有写锁。
  • 如果当前有其他写线程或读线程正在执行(active_writers > 0 或 readers > 0),写线程需要等待。
  1. 写优先
  • 写线程释放锁时,优先唤醒其他写线程(避免写线程饥饿)。
  • 如果没有写线程等待,才唤醒所有读线程。
pthread_rwlock_t rwlock; // 创建读写锁
pthread_rwlock_init(&rwlock, NULL);
pthread_rwlock_rdlock(&rwlock); //读加锁,允许多个读
pthread_rwlock_wrlock(&rwlock); //写加锁
pthread_rwlock_unlock(&rwlock); //解说,读写都统一
pthread_rwlock_destroy(&rwlock);

条件变量

本身不是锁,锁mutex的基础上增加条件等待,只有在其他线程通知或超时的情况下条件才会满足

pthread_cond_t cond;//创建条件变量,内部也有阻塞队列
pthread_cond_init(&cond,NULL);
pthread_cond_wait(&cond,&mutex);
pthread_cond_signal(&cond);//从阻塞队列中拿出至少一个线程
pthread_cond_broadcast(&cond);//将所有线程移除阻塞队列
pthread_cond_destroy(&cond);

重点

  1. wait过程(消费者):先将mutex解锁并将线程移入cond的阻塞队列中,等待条件满足,条件满足时,会重新加锁;
  2. signal/broadcast过程(生产者):将至少一个/全部线程移出cond的阻塞队列 image.png
  3. 虚假唤醒:由于可能会将多个消费者线程同时移出条件阻塞队列,而产品只有一个时,就会出现错误,因此消费者需要重复判断是否满足条件:
while (condition_not_met) { 
    // 必须用while循环检查条件 
    pthread_cond_wait(&cond, &mutex); // 原子操作:解锁+阻塞 
}
  1. 所有使用条件变量的代码,都必须用while循环检查条件!

信号量semaphore

能用于进程和线程,相当于初始值为N的互斥量mutex,N表示可以同时访问共享数据的线程数

sem_t sem;
sem_init(&sem,0,5);//允许5个线程同时操作
sem_wait(&sem);//--操作,<0则阻塞
sem_trywait(&sem);//尝试--,小于0则不--
sem_timedwait(&sem);//超时则唤醒,需搭配timespec结构体
sem_post(&sem);//++ ,<=0则唤醒
sem_destroy(&sem);