您的位置:首页 > 运维架构 > Linux

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

2013-06-28 13:37 330 查看


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

2012
年 11 月 27 日

概述

上一篇介绍了共享内存,已经属于比较高级的层次。本篇介绍一下多线程/多进程最基础的问题,同步。

为了允许在线程或进程间共享数据,同步常常是必需的,也就是我们常说要用锁(当然锁通常也是性能瓶颈,现在无锁架构正在越发流行)。互斥锁和条件变量则是同步的基本组成部分。互斥锁和条件变量在同一进程下的所有线程内是共享的,所有它天然可以用于线程同步。如果将互斥锁和条件变量存放在多个进程的共享区内,则同样可以用于进程间同步。(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
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: