Linux进程通信[2]-互斥锁和条件变量

Linux进程通信[2]-互斥锁和条件变量

概述

上一篇介绍了共享内存,已经属于比较高级的层次。本篇介绍一下多线程/多进程最基础的问题,同步。
为了允许在线程或进程间共享数据,同步常常是必需的,也就是我们常说要用锁(当然锁通常也是性能瓶颈,现在无锁架构正在越发流行)。互斥锁和条件变量则是同步的基本组成部分。互斥锁和条件变量在同一进程下的所有线程内是共享的,所有它天然可以用于线程同步。如果将互斥锁和条件变量存放在多个进程的共享区内,则同样可以用于进程间同步。(Posix标准)

互斥锁

互斥锁用于保护临界区(critical section),保证在任何时刻只有一个线程/进程在执行其中的代码。保护一个临界区的代码通常轮廓如下:

1 lock_the_mutex(...);
2 //do anything one by one
3 unlock_the_mutex(...);

在实际代码中,我们通常使用如下的数据机构和函数。

01 #include <pthread.h>
02 //pthread_mutex_t 是锁的定义
03 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZE;
04  
05 //尝试对ptr上锁,否则一直阻塞
06 int pthread_mutex_lock(pthread_mutex_t *ptr);
07 //尝试对ptr上锁,失败则直接返回
08 int pthread_mutex_trylock(pthread_mutex_t *ptr);
09 //解锁
10 int pthread_mutex_unlock(pthread_mutex_t *ptr);

条件变量

条件变量(condition)不同于互斥锁,它主要用于等待。因为我们在线程/进程同步时,通常都需要等待其他线程/进程完成任务再继续自己的任务。这时,仅仅使用mutex就无法完美的解决这个问题。假设我们只使用mutex,则需要锁上一个mutex然后查询,如果没有前序任务则解锁,然后隔断时间再继续上述过程。而借助条件变量,我们则可以大大简化这个过程。在锁上mutex后,如果没有前序任务则调用wait函数,系统会自动释放mutex并且等待前置信号的到达,且信号到达后还是拥有mutex。
下面是condition的常用函数:

1 #include <pthread.h>
2 //pthread_mutex_t 是条件变量的定义
3 static pthread_cond_t lock = PTHREAD_COND_INITIALIZER;
4  
5 //等待条件变量 cptr
6 int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);
7 //发送条件变量 cptr
8 int pthread_cond_signal(pthread_cond_t *cptr);

每个条件变量总有一个互斥锁与之关联。(个人猜测原因:因为我们等待条件变量时候,需要释放mutex,交给其他线程

样例

这里用一个简单的生产者-消费者模型来演示如何使用mutex和condition。

01 #include <pthread.h>
02  
03 pthread_mutex_t p_mutex = PTHREAD_MUTEX_INITIALIZER;
04 pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER;
05 pthread_cond_t c_cond = PTHREAD_COND_INITIALIZER;
06  
07 int LEN = 100;
08 int arr[LEN];
09 int nready = 0;
10  
11 void *produce(void *arg) {
12     int i = 0;
13     for (;;) {
14         //多线程生产
15         pthread_mutex_lock(&p_mutex);
16         if (i > LEN) {
17             pthread_mutex_unlock(&p_mutex);
18             break;
19         }
20         arr[i++] = i;
21         pthread_mutex_unlock(&p_mutex);
22  
23         //需要和消费进程 同步 完成数
24         pthread_mutex_lock(&c_mutex);
25         if (nready == 0) {
26             //通知消费进程
27             pthread_cond_signal(&c_cond);
28         }
29         nready++;
30         pthread_mutex_unlock(&c_mutex);
31     }
32 }
33  
34 void *consume(void *arg) {
35     //单线程消费
36     for (int i = 0; i < LEN; ++i) {
37         pthread_mutex_lock(&c_mutex);
38         if (nready == 0) {
39             //等待消费者通知
40             pthread_cond_wait(&c_cond, &c_mutex);
41         }
42         nready--;
43         pthread_mutex_unlock(&c_mutex);
44  
45         //do something for arr[i];
46     }
47 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值