出招表七:信号量(信号量其实和自旋锁是一样的,就是有一点不同:当获取不到信号量时,进程不会原地打转而是进入休眠等待状态)
Linux系统中与信号量相关的操作主要有一下4种:
1)定义信号量 struct semaphore sem;
2)初始化信号量
void sema_init (struct semphore *sem, int val); //设置sem为val
void init_MUTEX(struct semaphore *sem); //初始化一个用户互斥的信号量sem设置为1
void init_MUTEX_LOCKED(struct semaphore *sem); //初始化一个用户互斥的信号量sem设置为0
DECLARE_MUTEX(name); //该宏定义信号量name并初始化1
DECLARE_MUTEX_LOCKED(name); //该宏定义信号量name并初始化0
3)获得信号量
void down(struct semaphore *sem); //该函数用于获取信号量sem,会导致睡眠,不能被信号打断,所以不能在中断上下文使用。
int down_interruptible(struct semaphore *sem); //因其进入睡眠状态的进程能被信号打断,信号也会导致该函数返回,这是返回非0。
int down_trylock(struct semaphore *sem);//尝试获得信号量sem,如果能够获得,就获得并返回0,否则返回非0,不会导致调用者睡眠,可以在中断上下文使用
一般这样使用
if(down_interruptible(&sem))
{
return - ERESTARTSYS;
}
4)释放信号量
void up(struct semaphore *sem); //释放信号量sem,唤醒等待者
信号量一般这样被使用,如下所示:
//定义信号量
DECLARE_MUTEX(mount_sem);
down(&mount_sem);//获取信号量,保护临界区
…
critical section //临界区
…
up(&mount_sem);
好了,下边给大家一个例子看看使用信号量来实现设备只能被一个进程打开的例子:
static DECLARE_MUTEX(xxx_lock);//定义互斥锁
static int xxx_open(struct inode *inode, struct file *filp)
{
…
if(down_trylock(&xxx_lock)) //获得打开锁
return – EBUSY; //设备忙
…
return 0;//成功
}
static int xxx_release(struct inode *inode, struct file *filp)
{
up(&xxx_lock); //释放打开锁
return 0;
}
在上面介绍的有关信号量的操作中,我们提到了一个问题就是信号量的初始化问题,一般对信号量的初始化是没有限制的,但如果信号量被初始化为0,则它可以用于同步,说到这里,就不得不介绍新的一招了
出招表八:同步(它意味着一个执行单元的继续执行需要等待另一个执行单元完成其事,保证了执行的先后顺序)
在这个图中,执行单元A执行代码区域b之前,必须等待执行单元B执行完代码单元c,而信号量刚好可辅助完成这一同步过程.
这时你可能要问,像这样的同步,在现实中可是常常遇到.比如,报名时必须等前一项完成了才能完成后一项..等等,是不是同步就这么一种方式啊..
呵呵,真聪明,小菜终于长大了,成为大菜了.其实,Linux系统提供了一种更好的同步机制----完成量,好吧,看在你求学若渴的份上,就把它一起传授给你了,不收费哦,呵呵
出招表九:完成量(completion),它用于一个执行单元等待另一个执行单元执行完某事
使用方法:1)定义完成量
struct completion my_completion;
2)初始化
init_completion(&my_completion); //要是觉得这两步麻烦,就再给你来个宏即定义又初始化DECLARE_COMPLETION(my_completion);
3)等待完成量
void wait_for_completion(structcompletion *c); //等待一个completion被唤醒
wait_for_completion_interruptible(struct completion *c); //可中断的wait_for_completion
unsigned long wait_for_completion_timeout(struct completion *x,unsigned long timeout); //带超时处理的wait_for_completion
4)唤醒完成量
void complete(struct completion *c); //只唤醒一个等待的执行单元。
void complete_all(struct completion *c); //唤醒所有等待这个完成量的执行单元
瞧我这记性,说了这么多,怎么就忘了给出completion结构体呢:
struct completion
{
unsigned int done;//标志是否已经做完,未做完就是负值,代表等待个数,完成为0
wait_queue_head_t wait;
}
如果觉得不太理解,不过瘾,就给你来张图:
这下感觉怎样,好多了吧...
说句真的,我都没想到,这点东西要将那么久,虽然不愿意,但只能说:欲知后事如何,咱们下回接着再聊..