• 【转】工作队列学习


    好文:http://blog.chinaunix.net/uid-24148050-id-296982.html

    首先要注意本文的两个概念:(1)使用内核提供的工作队列, (2)自己创建工作队列

    http://blog.csdn.net/fontlose/article/details/8286445
    工作队列是一种将工作推后执行的形式,交由一个内核线程去执行在进程上下文执行,其不能访问用户空间。最重要特点的就是工作队列允许重新调度甚至是睡眠。
    工作队列子系统提供了一个默认的工作者线程来处理这些工作。默认的工作者线程叫做events/n,这里n是处理器的编号,每个处理器对应一个线程,也可以自己创建工作者线程。

     工作的定义

        typedef void (*work_func_t)(struct work_struct *work);
        
        定义中初始化处理函数
        DECLARE_WORK(n, f);
       
        #define DECLARE_WORK(n, f) struct work_struct n = __WORK_INITIALIZER(n, f)
        #define __WORK_INITIALIZER(n, f) {      
    .data = WORK_DATA_INIT(0),    
    .entry = { &(n).entry, &(n).entry },
    .func = (f)      
         }
     
        先定义中后初始化处理函数
        struct work_struct 
        INIT_WORK(struct work_struct *work, func_t);
        #define INIT_WORK(_work, _func)
    do {                        
    __INIT_WORK((_work), (_func), 0);
    } while (
    在使用带delay的函数或宏时使用DECLARE_DELAYED_WORK定义和INIT_DELAYED_WORK初始化。

    1.使用内核提供的共享列队
         对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。
         int schedule_work(struct work_struct *work);
     
         确保没有工作队列入口在系统中任何地方运行。
         void flush_scheduled_work(void);
     
         延时执行一个任务
         int schedule_delayed_work(struct delayed_struct *work, unsigned long delay);
     
         从一个工作队列中去除入口;
         int cancel_delayed_work(struct delayed_struct *work);
     
    测试例子  
    void myfunc(struct work_struct*ws);
    DECLARE_WORK(mywork,myfunc);                  //定义
     
     
    void myfunc(struct work_struct*ws)
    {
       printk(KERN_ALERT "myfunc current->pid %d ",current->pid);
       ssleep(1);
       printk(KERN_ALERT "myfunc current->pid %d ",current->pid);
       ssleep(1);
       printk(KERN_ALERT "myfunc current->pid %d ",current->pid);
       ssleep(1);
    }
     
    在加载模块时调用
    schedule_work(&mywork);
    printk(KERN_ALERT "main current->pid  %d " ,current->pid);
     
     
    在卸载模块的时调用
    cancel_delayed_work(&mywork);
    测试结果
    输出的pid
    main current->pid  2883                                                         
    myfunc current->pid 4                                                           
    myfunc current->pid 4                                   
    myfunc current->pid 4 
     
    [root@fontlose module]# ps                                                      
      PID USER       VSZ STAT COMMAND                                               
        1 root      2108 S    init                                                  
        2 root         0 SW   [ksoftirqd/0]                                         
        3 root         0 SW   [watchdog/0]                                          
        4 root         0 SW<  [events/0]   
     
    myfunc运行在pid为4 的进程中,查看pid为4的进程为events/0,使用内核提供的共享列队,列队是保持顺序执行的,做完一个工作才做下一个,如果一个工作内有耗时大的处理如阻塞等待信号或锁,那么后面的工作都不会执行。如果你不喜欢排队或不好意思让别人等太久,那么可以创建自己的工作者线程,所有工作可以加入自己创建 的工作列队,列队中的工作运行在创建的工作者线程中。
     
    2.使用自定义列队 
    创建工作列队使用3个宏 成功后返回workqueue_struct *指针,并创建了工作者线程。三个宏主要区别在后面两个参数singlethread和freezeable,singlethread为0时会为每个 cpu上创建一个工作者线程,为1时只在当前运行的cpu上创建一个工作者线程。freezeable会影响内核线程结构体thread_info的 PF_NOFREEZE标记
      if (!cwq->freezeable)
            current->flags |= PF_NOFREEZE;
        set_user_nice(current, -5);
    在线程函数内设置了测试点如下
        if (cwq->freezeable)
            try_to_freeze();
    如果设置了PF_NOFREEZE这个flag,那么系统挂起时候这个进程不会被挂起。
    主要函数
    #define create_workqueue(name) __create_workqueue((name), 0, 0)                          //多处理器时会为每个cpu创建一个工作者线程              
    #define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1)       //只创建一个工作者线程,系统挂起是线程也挂起
    #define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0)    //只创建一个工作者线程,系统挂起是线程线程不挂起
    以上三个宏调用__create_workqueue函数定义
    extern struct workqueue_struct *__create_workqueue(const char *name,int singlethread, int freezeable);
     
    释放创建的工作列队资源
    void destroy_workqueue(struct workqueue_struct *wq)
     
    延时调用指定工作列队的工作
    queue_delayed_work(struct workqueue_struct *wq,struct delay_struct *work, unsigned long delay)
     
    取消指定工作列队的延时工作
    cancel_delayed_work(struct delay_struct *work)
     
    将工作加入工作列队进行调度
    queue_work(struct workqueue_struct *wq, struct work_struct *work)
     
    等待列队中的任务全部执行完毕。
    void flush_workqueue(struct workqueue_struct *wq);
     
    主要测试代码
    void myfunc(struct work_struct*ws);
     
    struct workqueue_struct *wqueue;
    DECLARE_WORK(mywork,myfunc);  
     
    void myfunc(struct work_struct*ws)
    {
       printk(KERN_ALERT "myfunc 1 current->pid %d ",current->pid);
       ssleep(1);
       printk(KERN_ALERT "myfunc 2 current->pid %d ",current->pid);
       ssleep(1);
       printk(KERN_ALERT "myfunc 3 current->pid %d ",current->pid);
       ssleep(1);
    }
     
    在模块加载是执行
     wqueue=create_workqueue("myqueue");
     queue_work(wqueue,&mywork);  
     printk(KERN_ALERT "main current->pid  %d " ,current->pid);
     
     
    测试结果
    main current->pid  1010            
                                               
    myfunc 1 current->pid 1016                                                      
    myfunc 2 current->pid 1016                              
    myfunc 3 current->pid 1016   
     
    ps
    ....
    1016 root         0 SW<  [myqueue/0] 
     
    可见函数运行在pid为1016的进程中,ps查看进程名为myqueue/0.
     
     
    实例说明
    1.使用自定义工作队列
     
    //=========
    #include>linux /kernel.h>
    #include>linux/module.h
    #include>linux/proc_fs.h>
    #include>linux/workqueue.h>
    #include>linux/sched.h>
    #include>linux/init.h>
    #include>linux/interrupt.h>
    #include>linux/delay.h>
    struct workqueue_struct *test_wq;  
    struct delayed_work test_dwq;  
      
    void delay_func(struct work_struct *work);  
      
    void delay_func(struct work_struct *work)  
    {  
        int i;  
      
        printk(KERN_INFO "My name is delay_func! ");  
        for (i = 0; i < 3; i++) {  
            printk(KERN_ERR "delay_fun:i=%d ", i);  
            msleep(1000);  
        }  
    }  
      
    static int __init example_init(void)  
    {  
        int i;  
        int ret;  
      
        test_wq = create_workqueue("test_wq");  
        if (!test_wq) {  
            printk(KERN_ERR "No memory for workqueue ");  
            return 1;     
        }  
        printk(KERN_INFO "Create Workqueue successful! ");  
      
        INIT_DELAYED_WORK(&test_dwq, delay_func);  
          
        ret = queue_delayed_work(test_wq, &test_dwq, 5000);  
        printk(KERN_INFO "first ret=%d! ", ret);  
          
        for (i = 0; i < 3; i++) {   
            printk(KERN_INFO "Example:ret= %d,i=%d ", ret, i);  
            msleep(100);  
        }  
      
        ret = queue_delayed_work(test_wq, &test_dwq, 0);  
        printk(KERN_INFO "second ret=%d! ", ret);  
      
        return 0;  
    }  
      
    static void __exit example_exit(void)  
    {  
        int ret;  
        ret = cancel_delayed_work(&test_dwq);  
        flush_workqueue(test_wq);  
        destroy_workqueue(test_wq);  
        printk(KERN_INFO "Goodbay! ret=%d ", ret);  
    }  
    module_init(example_init);  
    module_exit(example_exit);  
    MODULE_LICENSE("GPL");  
    运行结果:
    kernel: Create Workqueue successful!  
    kernel: first ret=1!  
    kernel: Example:ret= 1,i=0  
    kernel: Example:ret= 1,i=1  
    kernel: Example:ret= 1,i=2  
    kernel: second ret=0!  
    kernel: Goodbay! ret=1  
    kernel: Create Workqueue successful! 
    说明将任务添加到工作队列后,如果工作队列还在执行该任务,则queue_delayed_work()返回1,否则返回0,如上实例所述;
    主线程delay_wq将任务添加到工作队列后,使得工作队列在延迟delay后执行函数delay_func(),而delay_wq线程继续执行;
     
    2.使用内核工作队列实例

    #include>linux/module.h>
    #include>linux/init.h>
    #include>linux/kernel.h>
    #include>linux/net.h>
    #include>net/sock.h>
    #include>linux/in.h>
    #include>linux/types.h>
    #include>linux/kthread.h>
    #include>linux/wait.h>
    #include>linux/skbuff.h>
    #include>linux/string.h>
    #include>asm-generic/unaligned.h>
    #include>linux/sysctl.h>
    #include>linux/netfilter.h>
    #include>linux/netfilter_ipv4.h>
    #include>asm/checksum.h>
    #include>linux/ip.h>
    #include>linux/workqueue.h>

    #define err(msg) printk(KERN_INFO "%s failed. ", msg)

    static void defense_work_handler(struct work_struct *work);

    static DECLARE_DELAYED_WORK(defense_work, defense_work_handler);

    static void defense_work_handler(struct work_struct *work)
    {
        printk(KERN_INFO "defense_work_handler function. ");
    }

    static int __init main_init(void)
    {
        schedule_delayed_work(&defense_work, 3 * HZ);

        return 0;
    }

    static void __exit main_exit(void)
    {
        cancel_delayed_work_sync(&defense_work);
    }

    module_init(main_init);
    module_exit(main_exit);
    MODULE_LICENSE("GPL");

  • 相关阅读:
    分治法解决寻找数组中最大最小值的问题
    bootstrap动画进度条
    关于bootstrap中css样式与自己设置的css样式相撞问题
    css引入外部字体
    清除浮动
    四叶玫瑰数
    水仙花数
    nginx 配置文件服务器
    springboot 自定义拦截器 防止恶意请求
    springboot 自定义异常
  • 原文地址:https://www.cnblogs.com/emlslxl/p/5868748.html
Copyright © 2020-2023  润新知