并发控制____完成量(comletion)

来源:互联网 发布:多个数最大公约数算法 编辑:程序博客网 时间:2024/06/05 10:27

 

    完成量用于一个执行单元等待另一个执行单元完成某些工作。强调代码片或执行单元的执行顺序,就用完成量completion。

    相关文件#include <linux/wait.h>

 

1. 定义:

如: struct completion my_completion;

因my_completion是多个执行单元的共享变量,是否在同一个文件中,自行决定要不要定义成static。

/* * struct completion - structure used to maintain state for a "completion" * * This is the opaque structure used to maintain the state for a "completion". * Completions currently use a FIFO to queue threads that have to wait for * the "completion" event. * * See also:  complete(), wait_for_completion() (and friends _timeout, * _interruptible, _interruptible_timeout, and _killable), init_completion(), * and macros DECLARE_COMPLETION(), DECLARE_COMPLETION_ONSTACK(), and * INIT_COMPLETION(). */struct completion {unsigned int done;wait_queue_head_t wait;};


 

2. 初始化:

如: init_completion(&my_completion);

初始化后completion.done为0

/** * init_completion - Initialize a dynamically allocated completion * @x:  completion structure that is to be initialized * * This inline function will initialize a dynamically created completion * structure. */static inline void init_completion(struct completion *x){x->done = 0;init_waitqueue_head(&x->wait);}

 

    定义、初始化一起搞定:

如:DECLARE_COMPLETION(my_completion);

/** * DECLARE_COMPLETION - declare and initialize a completion structure * @work:  identifier for the completion structure * * This macro declares and initializes a completion structure. Generally used * for static declarations. You should use the _ONSTACK variant for automatic * variables. */#define DECLARE_COMPLETION(work) \struct completion work = COMPLETION_INITIALIZER(work)


3. 等待

如:wait_for_completion(&my_completion);

wait_for_completion_interruptible(&my_completion);

区别:后者在阻塞等待时可以被信号打断

调用wait_xxx函数时,每调用一次wait,comletion.done就减1,直到0时就阻塞,继续等待其他地方的completion完成的唤醒。

wait_for_completion_killable()可被SIGKILL打断。

unsigned long wait_for_completion_timeout(struct completion *x,unsigned long timeout);超时等待不到就返回

/** * wait_for_completion: - waits for completion of a task * @x:  holds the state of this particular completion * * This waits to be signaled for completion of a specific task. It is NOT * interruptible and there is no timeout. * * See also similar routines (i.e. wait_for_completion_timeout()) with timeout * and interrupt capability. Also see complete(). */void __sched wait_for_completion(struct completion *x){wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE, 0);}int wait_for_completion_interruptible(struct completion *x);

 

4. 唤醒

    一般使用时,一个completion被一个执行单元阻塞等待,也有可能会有多个,这个时候complete()一次只能唤醒一个,而complete_all()一次可以唤醒多个等待该completion的执行单元,唤醒次序跟阻塞次序同,即FIFO。

    complete()使done加1,而complete_all()将使done设为UINT_MAX/2,这就是为什么可以唤醒所有等待执行单元,除非等待者超过UINT_MAX/2个。

 

/** * complete: - signals a single thread waiting on this completion * @x:  holds the state of this particular completion * * This will wake up a single thread waiting on this completion. Threads will be * awakened in the same order in which they were queued. * * See also complete_all(), wait_for_completion() and related routines. * * It may be assumed that this function implies a write memory barrier before * changing the task state if and only if any tasks are woken up. */void complete(struct completion *x){unsigned long flags;spin_lock_irqsave(&x->wait.lock, flags);x->done++;__wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);spin_unlock_irqrestore(&x->wait.lock, flags);}void complete_all(struct completion *);


5. 示例

这个示例来自linux 3.4内核中的keyboard/hil_kbd.c。

    在初始化时,init_completion,写命令,然后wait_completion,在中断的命令处理函数后会调用completion,使得wait_completion代码的地方返回,这样的过程重复多次,使多个初始化命令完成。

struct hil_dev {struct input_dev *dev;struct serio *serio;/* Input buffer and index for packets from HIL bus. */hil_packet data[HIL_PACKET_MAX_LENGTH];int idx4; /* four counts per packet *//* Raw device info records from HIL bus, see hil.h for fields. */charidd[HIL_PACKET_MAX_LENGTH];/* DID byte and IDD record */charrsc[HIL_PACKET_MAX_LENGTH];/* RSC record */charexd[HIL_PACKET_MAX_LENGTH];/* EXD record */charrnm[HIL_PACKET_MAX_LENGTH + 1];/* RNM record + NULL term. *//*------->****<-----completion定义*/struct completion cmd_done;bool is_pointer;/* Extra device details needed for pointing devices. */unsigned int nbtn, naxes;unsigned int btnmap[7];};/*发生中断,会调用命令响应函数hil_dev_handle_command_response,其中会执行completion*/static irqreturn_t hil_dev_interrupt(struct serio *serio,unsigned char data, unsigned int flags){//...hil_dev_handle_command_response(dev);//...}/*命令响应后,会唤醒等待该命令结果的执行单元*/static void hil_dev_handle_command_response(struct hil_dev *dev){hil_packet p;char *buf;int i, idx;idx = dev->idx4 / 4;p = dev->data[idx - 1];switch (p & HIL_PKT_DATA_MASK) {case HIL_CMD_IDD:buf = dev->idd;break;case HIL_CMD_RSC:buf = dev->rsc;break;case HIL_CMD_EXD:buf = dev->exd;break;case HIL_CMD_RNM:dev->rnm[HIL_PACKET_MAX_LENGTH] = 0;buf = dev->rnm;break;default:/* These occur when device isn't present */if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {/* Anything else we'd like to know about. */printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);}goto out;}for (i = 0; i < idx; i++)buf[i] = dev->data[i] & HIL_PKT_DATA_MASK;for (; i < HIL_PACKET_MAX_LENGTH; i++)buf[i] = 0; out:/*------->****<-----completion唤醒等待该资源的执行单元*/complete(&dev->cmd_done);}/*连接成功后,多次初始化comletion,即初始化completion.done为0,然后写命令,等待命令执行结果 *可重复初始化,等待,返回 */static int hil_dev_connect(struct serio *serio, struct serio_driver *drv){//.../* Get device info.  MLC driver supplies devid/status/etc. */init_completion(&dev->cmd_done);serio_write(serio, 0);serio_write(serio, 0);serio_write(serio, HIL_PKT_CMD >> 8);serio_write(serio, HIL_CMD_IDD);error = wait_for_completion_killable(&dev->cmd_done);/*只可被SIGKILL中断,或者有人调用了completion,才能返回*/if (error)goto bail1;init_completion(&dev->cmd_done);serio_write(serio, 0);serio_write(serio, 0);serio_write(serio, HIL_PKT_CMD >> 8);serio_write(serio, HIL_CMD_RSC);error = wait_for_completion_killable(&dev->cmd_done);if (error)goto bail1;init_completion(&dev->cmd_done);serio_write(serio, 0);serio_write(serio, 0);serio_write(serio, HIL_PKT_CMD >> 8);serio_write(serio, HIL_CMD_RNM);error = wait_for_completion_killable(&dev->cmd_done);if (error)goto bail1;init_completion(&dev->cmd_done);serio_write(serio, 0);serio_write(serio, 0);serio_write(serio, HIL_PKT_CMD >> 8);serio_write(serio, HIL_CMD_EXD);error = wait_for_completion_killable(&dev->cmd_done);if (error)goto bail1;//...}

0 0
原创粉丝点击