问一个completion的问题

发布于 2022-09-23 14:20:58 字数 95 浏览 10 评论 0

completion 可以使用一个线程唤醒另外一个线程。

那么它跟 wake_up_interruptible 有什么区别么?? 这个函数同样也能唤醒另外一个线程啊

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

攒眉千度 2022-09-30 14:20:58

completion是一种轻量级的机制,它允许一个线程告诉另一个线程工作已经完成。可以利用下面的宏静态创建completion:
DECLARE_COMPLETION(my_completion);
如果运行时创建completion,则必须采用以下方法动态创建和初始化:

  1. struct compltion my_completion;
  2. init_completion(&my_completion);
  3. completion的相关定义包含在kernel/include/linux/completion.h中:
  4. struct completion {
  5. unsigned int done;
  6. wait_queue_head_t wait;
  7. };
  8. #define COMPLETION_INITIALIZER(work)
  9.         { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
  10. #define DECLARE_COMPLETION(work)
  11.         struct completion work = COMPLETION_INITIALIZER(work)
  12. static inline void init_completion(struct completion *x)
  13. {
  14.     x->done = 0;
  15.     init_waitqueue_head(&x->wait);
  16. }

复制代码
要等待completion,可进行如下调用:
void wait_for_completion(struct completion *c);
触发completion事件,调用:
void complete(struct completion *c);      //唤醒一个等待线程
void complete_all(struct completion *c); //唤醒所有的等待线程
为说明completion的使用方法,将<<Linux设备驱动程序>>一书中的complete模块的代码摘抄如下:

  1. /*
  2. * complete.c -- the writers awake the readers
  3. */
  4. ------------------------------------------------------------
  5. #include <linux/module.h>
  6. #include <linux/init.h>
  7. #include <linux/sched.h>   /* current and everything */
  8. #include <linux/kernel.h> /* printk() */
  9. #include <linux/fs.h>      /* everything... */
  10. #include <linux/types.h>   /* size_t */
  11. #include <linux/completion.h>
  12. MODULE_LICENSE("Dual BSD/GPL");
  13. static int complete_major = 253; //指定主设备号
  14. DECLARE_COMPLETION(comp);
  15. ssize_t complete_read (
  16.     struct file *filp, char __user *buf,
  17.     size_t       count, loff_t       *pos)
  18. {
  19.     printk(KERN_DEBUG "process %i (%s) going to sleepn",
  20.             current->pid, current->comm);
  21.     wait_for_completion(&comp);
  22.     printk(KERN_DEBUG "awoken %i (%s)n", current->pid, current->comm);
  23.     return 0;
  24. }
  25. ssize_t complete_write (
  26.     struct file *filp, const char __user *buf,
  27.     size_t       count, loff_t            *pos)
  28. {
  29.     printk(KERN_DEBUG "process %i (%s) awakening the readers...n",
  30.             current->pid, current->comm);
  31.     complete(&comp);
  32.     return count;
  33. }
  34. struct file_operations complete_fops = {
  35.     .owner = THIS_MODULE,
  36.     .read = complete_read,
  37.     .write = complete_write,
  38. };
  39. int complete_init(void)
  40. {
  41.     int result;
  42.     result = register_chrdev(complete_major, "completion", &complete_fops);
  43.     if (result < 0)
  44.         return result;
  45.     if (complete_major == 0)
  46.         complete_major = result;
  47.     return 0;
  48. }
  49. void complete_cleanup(void)
  50. {
  51.     unregister_chrdev(complete_major, "completion");
  52. }
  53. module_init(complete_init);
  54. module_exit(complete_cleanup);

复制代码
该模块定义了一个简单的completion设备:任何试图从该设备中读取的进程都将等待,直到其他设备写入该设备为止。编译此模块的Makefile如下:
obj-m := complete.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD   := $(shell pwd)
default:
    $(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
    rm -f *.ko *.o *.mod.c
在linux终端中执行以下命令,编译生成模块,并进行动态加载
# make
# mknod completion c 253 0
# insmod complete.ko
再打开三个终端,一个用于读进程:
# cat completion
一个用于写进程:
# echo >completion
另一个查看系统日志:
# tail -f /var/log/messages
值得注意的是,当我们使用的complete_all接口时,如果要重复使用一个completion结构,则必须执行INIT_COMPLETION (struct completion c)来重新初始化它。可以在kernel/include/linux/completion.h中找到这个宏的定义:
#define INIT_COMPLETION(x) ((x).done = 0)
以下代码对书中原有的代码进行了一番变动,将唤醒接口由原来的complete换成了complete_all,并且为了重复利用completion结构,所有读进程都结束后就重新初始化completion结构,具体代码如下:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/sched.h>
  4. #include <linux/kernel.h>
  5. #include <linux/fs.h>
  6. #include <linux/types.h>
  7. #include <linux/completion.h>
  8. MODULE_LICENSE("Dual BSD/GPL");
  9. #undef KERN_DEBUG
  10. #define KERN_DEBUG "<1>"
  11. static int complete_major=253;
  12. static int reader_count = 0;
  13. DECLARE_COMPLETION(comp);
  14. ssize_t complete_read (struct file *filp,char __user *buf,size_t count,loff_t *pos)
  15. {
  16.     printk(KERN_DEBUG "process %i (%s) going to sleep,waiting for writern",current->pid,current->comm);
  17.     reader_count++;
  18.     printk(KERN_DEBUG "In read ,before comletion: reader count = %d n",reader_count);
  19.     wait_for_completion(&comp);
  20.     reader_count--;
  21.     printk(KERN_DEBUG "awoken %s (%i) n",current->comm,current->pid);
  22.     printk(KERN_DEBUG "In read,after completion : reader count = %d n",reader_count);
  23.     /*如果使用complete_all,则completion结构只能用一次,再次使用它时必须调用此宏进行重新初始化*/
  24.     if(reader_count == 0)
  25.         INIT_COMPLETION(comp);
  26.     return 0;
  27. }
  28. ssize_t complete_write(struct file *filp,const char __user *buf,size_t count,loff_t *pos)
  29. {
  30.     printk(KERN_DEBUG "process %i (%s) awoking the readers...n",current->pid,current->comm);
  31.     printk(KERN_DEBUG "In write ,before do complete_all : reader count = %d n",reader_count);
  32.     if(reader_count != 0)
  33.         complete_all(&comp);
  34.     printk(KERN_DEBUG "In write ,after do complete_all : reader count = %d n",reader_count);
  35.     return count;
  36. }
  37. struct file_operations complete_fops={
  38.     .owner = THIS_MODULE,
  39.     .read = complete_read,
  40.     .write = complete_write,
  41. };
  42. int complete_init(void)
  43. {
  44.     int result;
  45.     result=register_chrdev(complete_major,"complete",&complete_fops);
  46.     if(result<0)
  47.         return result;
  48.     if(complete_major==0)
  49.         complete_major =result;
  50.     printk(KERN_DEBUG    "complete driver test init! complete_major=%dn",complete_major);
  51.     printk(KERN_DEBUG "静态初始化completionn");
  52.     return 0;
  53. }
  54. void complete_exit(void)
  55. {
  56.     unregister_chrdev(complete_major,"complete");
  57.     printk(KERN_DEBUG    "complete driver    is removedn");
  58. }
  59. module_init(complete_init);
  60. module_exit(complete_exit);

复制代码
这里测试步骤和上述一样,只不过需要多打开几个终端来执行多个进程同时读操作。

山人契 2022-09-30 14:20:58

我知道啊, 但是这些功能同样能够用 waike_up_interrutpible 完成啊

花开雨落又逢春i 2022-09-30 14:20:58
void fastcall __sched wait_for_completion(struct completion *x)
{
    might_sleep();

    spin_lock_irq(&x->wait.lock);
    if (!x->done) {
        DECLARE_WAITQUEUE(wait, current);

        wait.flags |= WQ_FLAG_EXCLUSIVE;
        __add_wait_queue_tail(&x->wait, &wait);
        do {
            __set_current_state(TASK_UNINTERRUPTIBLE);
            spin_unlock_irq(&x->wait.lock);
            schedule();
            spin_lock_irq(&x->wait.lock);
        } while (!x->done);
        __remove_wait_queue(&x->wait, &wait);
    }
    x->done--;
    spin_unlock_irq(&x->wait.lock);
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文