Linux 条件变量,互斥量详解

C++ 解决线程同步的问题主要通过 互斥锁 mutex 与 条件变量 condition_varible 来完成。
Linux 封装的多线程库中封装了一系列的函数用于互斥和条件变量。

互斥量:mutex

Linux 主要函数:

pthread_mutex_t ;本质上是一个结构体类型的变量。
pthread_mutex_t mutex; mutex 只有两种取值 0 、 1;

常用函数:

#include
pthread_mutex_init(pthread_mutex_t *restrict mutex, 
                   const pthread_mutexattr_t *restrict attr);                                                
                   //返回值:若成功,返回0,否则,返回错误编号     
pthread_mutex_destroy(pthread_mutex_t *mutex); //销毁一个互斥锁
                   
pthread_mutex_lock(pthread_mutex_t *mutex);//加锁

pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁   

pthread_mutex_trylock(pthread_mutex_t *mutex);//尝试加锁,如果当前没有锁上即加锁,
                                              //如果锁上即返回。       

条件变量:condition_varible

pthread_cond_t 类型,
pthread_cond_t cond ;

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

//初始化一个条件变量

int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// 线程阻塞等待
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);//定时等待。超时解除阻塞

int pthread_cond_signal(pthread_cond_t *cond); //通知

int pthread_cond_broadcast(pthread_cond_t *cond);//广播

pthread_cond_wait() 用于阻塞当前线程,等待别的线程使用pthread_cond_signal()pthread_cond_broadcast来唤醒它。
pthread_cond_wait() 必须与pthread_mutex 配套使用。
pthread_cond_wait()函数一进入 wait 状态就会自动 release mutex。
当其他线程通过pthread_cond_signal()pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex。

静态初始化互斥量和条件变量:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥锁*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化条件变量*/

pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。

条件变量的虚假唤醒

最通俗的解释就是:当某个线程被条件变量唤醒之后,在通知唤醒那一瞬间,资源区的锁是打开的,这时候资源区相对于所有的线程来说都是可访问的,所以就会存在着另外一个线程在唤醒线程之前访问资源区,并修改了其中的数据,那么真正被唤醒的线程就会失去被唤醒的意义,即产生了虚假唤醒。
怎么避免虚假唤醒:
将 wait 函数 放置于一个while() 循环中,不断循环判断共享资源区的状态,避免被虚假唤醒。

  while (msg_list.empty()) //判断消息队列是否真为空?
    {
        pthread_cond_wait(&cond, &mtx);
    }

为什么需要互斥锁和条件变量一起协作来线程同步?

因为互斥量是一种锁,只有两种状态,加锁和未加锁,一旦某个共享资源区被加锁之后,另一个线程想要访问该资源区,如果没有条件变量的辅助,那么它就不得不频繁的去尝试申请访问,这回形成一种自旋锁的状态,他会占用 cpu 的资源。然而有了条件变量之后,条件变量会让另外的线程休眠等待,直到资源区被解锁之后直接通知另外的线程,这就节省了CPU的资源,条件变量的优势也更好的弥补了互斥锁的不足。

注:信号量和互斥锁也能实现线程同步,为什么通常使用条件变量?
最大区别,信号量不能一次性唤醒所有等待线程,而条件变量可以一次性的唤醒。

你可能感兴趣的:(Linux,高并发服务器,Linux,相关,C++,相关)