您的位置:首页 > 博客中心 > 网络系统 >

Linux互斥量&条件变量

时间:2022-04-03 12:57

互斥量 Mutex

互斥量
1. #include <pthread.h>  
2. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);  
3.   
4. int pthread_mutex_lock(pthread_mutex_t *mutex);  
5.   
6. int pthread_mutex_unlock(pthread_mutex_t *mutex);  
7.   
8. int pthread_mutex_destroy(pthread_mutex_t *mutex);  

linux中创建使用互斥量的方法如上,对于此和windows中非常类似,用于保护对于临界资源的互斥性访问。
如果将此互斥量放在进程的共享内存里,那么还可以通过此种方法实现进程的互斥访问,通过pthread_mutexattr_setpshared()来实现:
9. pthread_mutex_t *pSharedMutex;  //指向共享内存区的互斥量  
10. pthread_mutexattr_t mutexAttr;  //互斥量属性  
11.   
12. pSharedMutex = /*一个指向共享内存区的指针*/;  
13.   
14. pthread_mutexattr_init(&mutexAttr);  
15. pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);  
16. pthread_mutex_init(pSharedMutex, &mutexAttr);  

对于另外一些情况,比如在生产者和消费者模型中,如果使用互斥量来进行同步,那么每次在获取互斥量以后,线程还需要检测当前资源是否符合条件,不符合退出,这会造成轮询来浪费cpu的时间,对于这种情形应该使用条件变量

条件变量
条件变量用来等待,自动堵塞一个线程,直到指定的事件发生:
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞

条件变量使用上面的接口进行实现,需要注意的是要和一个mutex绑定进行使用,

#include <pthread.h>
#include <stdio.h>
#include<unistd.h>
#include <stdbool.h>
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

bool con = false;

void thread()
{
printf("%s\n", "child thread begin");

pthread_mutex_lock(&m);
while(!con) //避免虚假唤醒
pthread_cond_wait(&c, &m);
printf("%s\n", "child thread return");
pthread_mutex_unlock(&m);
}

int main()
{
pthread_t id;
int ret = pthread_create(&id, NULL, (void*)thread, NULL);
if(ret != 0)
{
printf("%s\n", "thread create failed");
}

sleep(1);
pthread_mutex_lock(&m);
printf("%s\n", "main thread");
pthread_mutex_unlock(&m);
con = true;
pthread_cond_signal(&c);
printf("%s\n", "main thread signal end");

pthread_join(id, NULL);
return 1;

}

pthread_cond_wait 执行的流程首先将这个mutex解锁, 然后等待条件变量被唤醒, 如果没有被唤醒, 该线程将一直休眠, 也就是说, 该线程将一直阻塞在这个pthread_cond_wait调用中, 而当此线程被唤醒时, 将自动将这个mutex加锁,然后再进行条件变量判断(原因是“惊群效应”,如果是多个线程都在等待这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。),如果满足,则线程继续执行,最后解锁,

需要注意:
唤醒丢失问题 
在线程并没有阻塞在条件变量上时,调用pthread_cond_signal或pthread_cond_broadcast函数可能会引起唤醒丢失问题。
唤醒丢失往往会在下面的情况下发生:
一个线程调用pthread_cond_signal或pthread_cond_broadcast函数; 
另一个线程正处在测试条件变量和调用pthread_cond_wait函数之间; 
没有线程正在处在阻塞等待的状态下。

调用pthread_cond_wait 前,要在函数外先锁住一个mutex,然后传给pthread_cond_wait 。
我知道,这样可以关闭 “条件检查与加入等待队列之间的时间窗”,
线程休眠前释放锁,醒来后再次加锁。
即:
加锁                     pthread_cond_wait  外
------------------- |----------------------------
1 判断条件             |
2 加入休眠队列 释放锁  | pthread_cond_wait 内
3 醒来         加锁    |

因为锁的存在,1,2是一个连续的操作,防止一二之间另一个线程使得条件满足

 

本类排行

今日推荐

热门手游