内核编程中常见的一种模式是,在当前线程只外初始化某个活动,然后等待该活动的结束。这个活动可能是,创建一个新的内核线程或者新的用户空间进程,在这种情况下,我们可以使用信号量来同步这两个任务
struct semaphore sem;
init_MUTEX_LOCKED(&sem);
start_external_task(&sem);
down(&sem);
外部任务working。。。。。
up(&sem);
使用信号的缺点:在通常的使用中,试图锁定某个信号量的代码会发现该信号量几乎总是可用;而如果存在针对该信号量的严重竞争,性能将受到影响(像上面那种情况,使用信号量在任务完成时进行通信,则调用down的线程几乎总是要等待)
目前,从2.4版内核开始,到2.6已经出现了"completion(完成)"接口。
completion是一种轻量级的机制,它允许一个线程告诉另一个线程某个工作已经完成
DECLARE_COMPLETION(my_completion); /* 创建completion */
/* 动态地创建和初始化completion */
struct completion my_completion;
init_completion(&my_completion);
/* 该函数执行一个非中断的等待,如果没有人会完成任务,则将产生一个不可杀的进程*/
void wait_for_completion(struct completion *c);
/* 触发实际的completion事件(completion通常是一个单次设备) */
void complete(struct completion *c); /*只唤醒一个等待进程*/
void complete_all(struct completion *c); /*允许唤醒所有等待进程*/
如果需要重复使用completion结构:
1.complete()使用完completion设备一次后然后被丢弃,如果仔细处理,completion结构也可以被重复使用,如果没有使用complete_all(),只要那个将要触发的事件是明确而不含糊的,就不会来任何问题,可重复使用一个completion结构.
2. 如果使用了complete_all,则必须在重复使用该结构之前重新初始化它,可以调用下面这个宏来快速执行重新初始化:
INIT_COMPLETION(struct completion c);
completion机制的典型使用是模块退出时的内核线程终止
当内核准备清除该模块时,exit函数会告诉该线程(内核线程while(1)循环)退出并等待completion,为了实现这个目的,内核包含了一个可用于这种线程的函数:
void complete_and_exit(struct completion *c,long retval);
阅读(1087) | 评论(0) | 转发(0) |