zoukankan      html  css  js  c++  java
  • 工作队列中的sleep导致控制台无法输入问题

    通常我们会在workqueue中调用msleep(50);之类的函数进行延时。而且是可行的。

    使用方法如下:

    =========================

    定义工作队列的一个工作线结构体:

    struct work_struct ch450_wq;

    初始化工作的服务函数:

    void wq_try_read_ch450_server(struct work_struct *work)

    {

        … …

        msleep(xx);

        … …

    }

    INIT_WORK(&ch450_wq,wq_try_read_ch450_server);

    在中断服务函数中将工作线程,挂载到全局工作队列,启动工作线程:

    static irqreturn_t ch450_kbd_irq(int irq, void *dev_id)
    {
        schedule_work(&ch450_wq);
        return IRQ_HANDLED;
    }

    ========================

        在通常情况下,上面的使用不会有问题,因为msleep(xx)很快会执行完。但是如果这个sleep较长就会出问题。例如:串口控制台无响应,flash文件

    系统中的文件无法操作,等。这些问题出现的原因是sleep将全局工作队列阻塞了。全局工作队列是一个内核线程。因此与这个工作队列相关的其它

    工作服务函数无法执行。解决办法是创建一个局部的工作队列,也就是另启一个工作队列线程,将工作服务函数挂到局部工作队列之中。举例如下:

    ========================

    定义一个局部工作队列:

    struct workqueue_struct *keventd_wqch450;

    创建局部工作队列(创建局部工作队列的方法有很多):

    keventd_wqch450 = create_workqueue("namexx");

    定义工作队列的一个工作线结构体:

    struct work_struct ch450_wq;

    初始化工作的服务函数:

    void wq_try_read_ch450_server(struct work_struct *work)

    {

        … …

        msleep(xx);

        … …

    }

    INIT_WORK(&ch450_wq,wq_try_read_ch450_server);

    在中断服务函数中将工作线程,挂载到局部工作队列,启动工作线程:

    static irqreturn_t ch450_kbd_irq(int irq, void *dev_id)
    {
        queue_work(keventd_wqch450,&ch450_wq);
        return IRQ_HANDLED;
    }

    ========================

    局部工作队列启动,相关函数如下:

    int queue_work( struct workqueue_struct *wq, struct work_struct *work );
    int queue_work_on( int cpu, struct workqueue_struct *wq, struct work_struct *work );
    int queue_delayed_work( struct workqueue_struct *wq,
    struct delayed_work *dwork, unsigned long delay );
    int queue_delayed_work_on( int cpu, struct workqueue_struct *wq,
    struct delayed_work *dwork, unsigned long delay );

    全局工作队列相关启动函数如下:

    int schedule_work( struct work_struct *work );
    int schedule_work_on( int cpu, struct work_struct *work );
    int scheduled_delayed_work( struct delayed_work *dwork, unsigned long delay );
    int scheduled_delayed_work_on(
    int cpu, struct delayed_work *dwork, unsigned long delay );

     

    参考如下:

    http://hi.baidu.com/ajoe/blog/item/8d85f2d3b59a71d1a8ec9a46.html

    延时处理一般用在中断的bottom-half中。
    tasklet 函数不能休眠,采用一步到位的延时方式。
    workqueue是可以休眠的,采用通用的延时方式。
    图 tasklet_struct 结构体的内部情况

    对结构体 tasklet_struct 的描述
    通过软中断机制来调度微线程,当机器处于严重软件中断负荷之下时, 可通过 ksoftirqd
    清单 1. 声明并调度微线程


    /* Declare a Tasklet (the Bottom-Half) */
    void tasklet_function( unsigned long data );

    DECLARE_TASKLET( tasklet_example, tasklet_function, tasklet_data );

    ...

    /* Schedule the Bottom-Half */
    tasklet_schedule( &tasklet_example );

    一个给定的微线程只运行在一个 CPU 中(就是用于调用该微线程的那个 CPU), 同一微线程永远不会同时运行在多个 CPU 中。 但是不同的微线程可以同时运行在不同的 CPU 中。

    清单 2. 微线程的创建以及 enable/disable 函数


    DECLARE_TASKLET( name, func, data );
    DECLARE_TASKLET_DISABLED( name, func, data);
    void tasklet_init( struct tasklet_struct *, void (*func)(unsigned long),
    unsigned long data );
    void tasklet_disable_nosync( struct tasklet_struct * );
    void tasklet_disable( struct tasklet_struct * );
    void tasklet_enable( struct tasklet_struct * );
    void tasklet_hi_enable( struct tasklet_struct * );

    清单 3. 微线程调度函数


    void tasklet_schedule( struct tasklet_struct * );
    void tasklet_hi_schedule( struct tasklet_struct * );
    清单 4. 微线程 kill 函数

    void tasklet_kill( struct tasklet_struct * );
    void tasklet_kill_immediate( struct tasklet_struct *, unsigned int cpu );

    图 3. 工作队列背后的处理过程
    处理流程图展示,从左到右,中断处理程序,结构体 work_struct,结构体 workqueue_struct,events/X,以及处理程序函数
    清单 6. 任务初始化宏


    INIT_WORK( work, func );
    INIT_DELAYED_WORK( work, func );
    INIT_DELAYED_WORK_DEFERRABLE( work, func );

    清单 7. 工作队列函数


    int queue_work( struct workqueue_struct *wq, struct work_struct *work );
    int queue_work_on( int cpu, struct workqueue_struct *wq, struct work_struct *work );

    int queue_delayed_work( struct workqueue_struct *wq,
    struct delayed_work *dwork, unsigned long delay );

    int queue_delayed_work_on( int cpu, struct workqueue_struct *wq,
    struct delayed_work *dwork, unsigned long delay );

    清单 8. 内核全局工作队列函数


    int schedule_work( struct work_struct *work );
    int schedule_work_on( int cpu, struct work_struct *work );

    int scheduled_delayed_work( struct delayed_work *dwork, unsigned long delay );
    int scheduled_delayed_work_on(
    int cpu, struct delayed_work *dwork, unsigned long delay );

    还有一些帮助函数用于清理或取消工作队列中的任务。想清理特定的任务项目并阻塞任务, 直到任务完成为止, 可以调用 flush_work 来实现。 指定工作队列中的所有任务能够通过调用 flush_workqueue 来完成。 这两种情形下,调用者阻塞直到操作完成为止。 为了清理内核全局工作队列,可调用 flush_scheduled_work

    int flush_work( struct work_struct *work );
    int flush_workqueue( struct workqueue_struct *wq );
    void flush_scheduled_work( void );

    还没有在处理程序当中执行的任务可以被取消。 调用 cancel_work_sync 将会终止队列中的任务或者阻塞任务直到回调结束(如果处理程序已经在处理该任务)。 如果任务被延迟,可以调用 cancel_delayed_work_sync

    int cancel_work_sync( struct work_struct *work );
    int cancel_delayed_work_sync( struct delayed_work *dwork );

    最后,可以通过调用 work_pending 或者 delayed_work_pending 来确定任务项目是否在进行中。

    work_pending( work );
    delayed_work_pending( work );
  • 相关阅读:
    网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
    【算法导论】贪心算法,递归算法,动态规划算法总结
    cocoa2dx tiled map添加tile翻转功能
    8月30日上海ORACLE大会演讲PPT下载
    【算法导论】双调欧几里得旅行商问题
    Codeforces Round #501 (Div. 3) B. Obtaining the String (思维,字符串)
    Codeforces Round #498 (Div. 3) D. Two Strings Swaps (思维)
    Educational Codeforces Round 89 (Rated for Div. 2) B. Shuffle (数学,区间)
    洛谷 P1379 八数码难题 (BFS)
    Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords (贪心)
  • 原文地址:https://www.cnblogs.com/leaven/p/2030174.html
Copyright © 2011-2022 走看看