精华内容
下载资源
问答
  • 理解 linux 工作队列

    千次阅读 2017-06-05 21:29:17
    linux 工作队列的理解

    在系统初始化的时候定义一个函数,这个函数在未来的某个情况下我会调用执行,但我不知道这个具体的时间是什么时候,所以我可以将这个任务储存在一个地方,然后在需要执行这个任务的时候调用它,这个任务被称为工作,这个储存任务的地方被称为工作队列。
    这样一个目的和中断系统一样,但我们为什么不用中断呢?
    IBM的工程师给出的解释:
    在中断上下文里,不能睡眠,不能阻塞;原因是中断上下文并不与任何进程关联,如在中断上下文睡眠,调度器将不能将其唤醒,所以在中断上下文中不能有导致内核进入睡眠的行为,如持有信号量,执行非原子的内存分配等。工作队列运行于进程上下文中 ( 他们通过内核线程执行 ),因此它完全可以睡眠,可以被调度,也可以被其他进程所抢占。(对进程上下文和中断上下文的理解推荐文章:http://blog.csdn.net/liusirboke/article/details/49681625

    如何使用工作队列?

    对于使用者,基本上只需要做 3 件事情,依次为:
    1. 创建工作项
    INIT_WORK(struct work_struct work, work_func_t func);
    这是一个宏,在运行时初始化工作项 work,并设置了回调函数 func
    2. 创建工作队列
    create_singlethread_workqueue(name)
    或者create_workqueue(name)
    3. 调度执行工作
    int schedule_work(struct work_struct *work);
    或者int queue_work(struct workqueue_struct *wq, struct work_struct *work);


    通过tp的代码来理解工作队列的原理。
    static struct work_struct touch_resume_work;
    首先定义一个任务
    static struct workqueue_struct *touch_resume_workqueue;
    定义一个工作队列
    static void touch_resume_workqueue_callback(struct work_struct *work)
    {
    TPD_DEBUG(“GTP touch_resume_workqueue_callback\n”);
    g_tpd_drv->resume(NULL);
    tpd_suspend_flag = 0;
    }
    定义调度这个工作所要执行的函数
    err = queue_work(touch_resume_workqueue, &touch_resume_work);
    调度这个工作
    err = cancel_work_sync(&touch_resume_work);
    在这个工作没有被执行之前取消调度

    probe 中:
    touch_resume_workqueue = create_singlethread_workqueue(“touch_resume”);
    创建工作队列,名字叫做 touch_resume ,用于存放一些任务,这些任务我们现在不想做。
    INIT_WORK(&touch_resume_work, touch_resume_workqueue_callback);
    初始化一个任务,这个任务绑定一个函数,这个函数现在不想执行,我只是告诉线程这有一个函数我后面可能会执行。


    我这就不明白了,干嘛还非得用个工作队列,想用的时候直接调用不得了?!
    照我现在的理解就是因为这个函数被执行时间的不确定性,所以要在我想要执行的时候随时就能调用,当这个工作所在的工作者线程被唤醒的时候,就可以执行这个函数了。整个linux系统在启动期间是按照规定的顺序执行一些代码,但在系统初始化完成之后你就不知道什么时候执行什么函数了,这个时候就需要随时能够把函数给到线程,让cpu去调度(不对,感觉解释的还是不对)。

    一张画的很好的图(出处:http://blog.csdn.net/xy010902100449/article/details/46346735
    这里写图片描述

    这里写图片描述
    这里写图片描述

    推荐文章:
    Linux 的并发可管理工作队列机制探讨
    https://www.ibm.com/developerworks/cn/linux/l-cn-cncrrc-mngd-wkq/

    展开全文
  • Linux 工作队列和等待队列

    千次阅读 2018-03-22 10:17:08
    schedule_work调度执行一个具体的任务,执行的任务...输入参数:@ workqueue_struct:指定的workqueue指针@work_struct:具体任务对象指针Linux 工作队列和等待队列的区别等待队列在内核中有很多用途,尤其适合用于...

    schedule_work
    调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue——keventd_wq输入参数:

    queue_work

    调度执行一个指定workqueue中的任务。输入参数:

    @ workqueue_struct:指定的workqueue指针

    @work_struct:具体任务对象指针

     

     

     

    Linux 工作队列和等待队列的区别

     

    等待队列

    在内核中有很多用途,尤其适合用于中断处理,进程同步及定时。我们在这里只说,

    进程经常必须等待某些事件的发生。例如,等待一个磁盘操作的终止,等待释放系统资源,或者

    等待时间经过固定的间隔。

     

    等待队列实现了在事件上的条件等待,希望等待特定事件的进程把自己放进合适的等待队列,并

    放弃控制权。因此。等待队列表示一组睡眠的进程,当某一条件为真时,由内核唤醒它们。

     

    等待队列由循环链表实现,其元素包括指向进程描述符的指针。每个等待队列都有一个等待队列头,

    等待队列头是一个类型为wait_queue_head_t的数据结构。

     

    等待队列链表的每个元素代表一个睡眠进程,该进程等待某一事件的发生,它的描述符地址存放在

    task字段中

     

    然而,要唤醒等待队列中所有的进程有时并不方便。例如,如果两个或多个进程在等待互斥访问某

    一个要释放的资源,仅唤醒等待队列中一个才有意义。这个进程占有资源,而其他进程继续睡眠

     

    可以用DECLARE_WAIT_QUEUE_HEAD(name)宏定义一个新的等待队列,该宏静态地声明和初始化名为

    name的等待队列头变量。 init_waitqueue_head()函数用于初始化已动态分配的wait queue head变量

     

    等待队列可以通过DECLARE_WAITQUEUE()静态创建,也可以用init_waitqueue_head()动态创建。进程把

    自己放入等待队列并设置成不可执行状态。

    使用set_current_state(TASK_INTERRUPTIBLE)和schedule()让线程休眠停在此处,然后用wakeup唤醒后继续执行

    工作队列workqueue

    它允许内核代码来请求在将来某个时间调用一个函数。用来处理不是很紧急事件

    的回调方式处理方法.

    工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是如果您写了一个函数,而您

    现在不想马上执行它,您想在将来某个时刻去执行它,那您用工作队列准没错

     

    如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上

    下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信

    号量时,在需要执行阻塞式的I/O操作时,它都会非常有用

     

    对INIT_WORK的理解

     

    以前内核里对这个函数是这样定义的 #define INIT_WORK(_work, _func, _data),可以理解为INIT_WORK会在你定义的_work工作队列里面增加一个工作任务,该任务就是_func。_func这个任务会需要一些数据作为参数,这个参数就是通过_data传递的。

        而现在看驱动的时候你会发现调用INIT_WORK的时候是只有两个参数,去掉了数据的部分。也许你会问怎么传递data呢,等下会讲述到。其实现在我对这个理解还是比较模糊,希望各位说说你们的理解,顺便也让我理解更透彻一点。看许多驱动模块的时候会发觉work就是一个工作队列,一般是结构体work_struct,主要的目的就是用来处理中断的。比如在中断里面要做很多事,但是比较耗时,这时就可以把耗时的工作放到工作队列。说白了就是系统延时调度的一个自定义函数。
       现在已goodix的触摸屏列举一下步骤:
       1. 在探测函数里goodix_ts_probe初始化
       INIT_WORK(&ts->work, goodix_ts_work_func);//struct work_struct  work,ts是client私有数据结构体
       主要目的就是因为就算没有中断,在第一次开机时也有检测设备,所以这个任务一开始就执行,只不过到后来中断发生后就再执行.
       2. 现在当然轮到static void goodix_ts_work_func(struct work_struct *work)这个工作任务了
       在这个函数里会有一句:
       struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);
    这函数的主要目的就是解决前面所说的我们的data跑哪去了,使用container_of这个函数来求出我们的data的指针
       3.当然你不能忘记注册你的中断函数了
    request_irq(client->irq, goodix_ts_irq_handler,pdata->irq_edge ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING,client->name, ts);
    所以用一个结构体ts就可以把中断,任务,设备名等全部囊括进来
    我理解就差不多是这样的。希望大叔级任务指出不正之处。
     
    展开全文
  • Linux 工作队列和等待队列的区别

    千次阅读 2018-05-24 11:26:33
    wait queue是一种「任务队列」,可以把一些进程放在上面睡眠等待某个事件,强调静态多一些,重点在queue上,即它就是一个queue,这个queue如何调度,什么时候调度并不重要。对这2个容易混淆的队列做简单概念上的区别...
    work queue是一种bottom half,中断处理的后半程,强调的是动态的概念,即work是重点,而queue是其次。
    

    wait queue是一种「任务队列」,可以把一些进程放在上面睡眠等待某个事件,强调静态多一些,重点在queue上,即它就是一个queue,这个queue如何调度,什么时候调度并不重要。

    对这2个容易混淆的队列做简单概念上的区别,怎么用?

     

    等待队列在内核中有很多用途,尤其适合用于中断处理,进程同步及定时。我们在这里只说,

    进程经常必须等待某些事件的发生。例如,等待一个磁盘操作的终止,等待释放系统资源,或者

    等待时间经过固定的间隔。

     

    等待队列实现了在事件上的条件等待,希望等待特定事件的进程把自己放进合适的等待队列,并

    放弃控制权。因此。等待队列表示一组睡眠的进程,当某一条件为真时,由内核唤醒它们。

     

    等待队列由循环链表实现,其元素包括指向进程描述符的指针。每个等待队列都有一个等待队列头,

    等待队列头是一个类型为wait_queue_head_t的数据结构。

     

    等待队列链表的每个元素代表一个睡眠进程,该进程等待某一事件的发生,它的描述符地址存放在

    task字段中

     

    然而,要唤醒等待队列中所有的进程有时并不方便。例如,如果两个或多个进程在等待互斥访问某

    一个要释放的资源,仅唤醒等待队列中一个才有意义。这个进程占有资源,而其他进程继续睡眠

     

    可以用DECLARE_WAIT_QUEUE_HEAD(name)宏定义一个新的等待队列,该宏静态地声明和初始化名为

    name的等待队列头变量。 init_waitqueue_head()函数用于初始化已动态分配的wait queue head变量

     

    等待队列可以通过DECLARE_WAITQUEUE()静态创建,也可以用init_waitqueue_head()动态创建。进程把

    自己放入等待队列并设置成不可执行状态。

     

     

    工作队列,workqueue,它允许内核代码来请求在将来某个时间调用一个函数。用来处理不是很紧急事件

    的回调方式处理方法.

    工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是如果您写了一个函数,而您

    现在不想马上执行它,您想在将来某个时刻去执行它,那您用工作队列准没错

     

    如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上

    下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信

    号量时,在需要执行阻塞式的I/O操作时,它都会非常有用

    展开全文
  • Linux工作队列实现机制

    千次阅读 2016-06-30 22:18:26
     把推后执行的任务叫做工作(work),描述它的数据结构为work_struct ,这些工作队列结构组织成工作队列(workqueue),其数据结构为workqueue_struct ,而工作线程就是负责执行工作队列中的工作。系统默

    本文转载自:http://blog.csdn.net/tommy_wxie/article/details/7204306

    工作项、工作队列和工作者线程

     把推后执行的任务叫做工作(work),描述它的数据结构为work_struct ,这些工作以队列结构组织成工作队列(workqueue),其数据结构为workqueue_struct ,而工作线程就是负责执行工作队列中的工作。系统默认的工作者线程为events。

     工作队列(work queue)是另外一种将工作推后执行的形式。工作队列可以把工作推后,交由一个内核线程去执行—这个下半部分总是会在进程上下文执行,但由于是内核线程,其不能访问用户空间。最重要特点的就是工作队列允许重新调度甚至是睡眠。

     通常,在工作队列和软中断/tasklet中作出选择非常容易。可使用以下规则:
        如果推后执行的任务需要睡眠,那么只能选择工作队列
        如果推后执行的任务需要延时指定的时间再触发,那么使用工作队列,因为其可以利用timer延时
        如果推后执行的任务需要在一个tick之内处理,则使用软中断或tasklet,因为其可以抢占普通进程和内核线程;
        如果推后执行的任务对延迟的时间没有任何要求,则使用工作队列,此时通常为无关紧要的任务

     实际上,工作队列的本质就是将工作交给内核线程处理,因此其可以用内核线程替换。但是内核线程的创建和销毁对编程者的要求较高,而工作队列实现了内核线程的封装,不易出错,所以我们也推荐使用工作队列。


     工作队列使用

     相关文件:

        kernel/include/linux/workqueue.h

        Kernel/kernel/workqueue.c


     工作队列的创建,有两种方式:

     1)静态创建:

        DECLARE_WORK(name,function); 定义正常执行的工作项

        DECLARE_DELAYED_WORK(name,function); 定义延后执行的工作项

     2)动态创建,运行时创建:

        通常在probe()函数中执行下面的操作来初始化工作项:

        INIT_WORK(&work, new_ts_work);

        INIT_DELAYED_WORK(&led_work,s0340_ledtime_scanf);

     

     工作队列待执行的函数原型是:

     typedef void(*work_func_t)(structwork_struct *work);

     这个函数会由一个工作者线程执行,因此,函数会运行在进程上下文中。默认情况下,允许响应中断,并且不持有任何锁。如果需要,函数可以睡眠。需要注意的是,尽管该函数运行在进程上下文中,但它不能访问用户空间,因为内核线程在用户空间没有相关的内存映射。通常在系统调用发生时,内核会代表用户空间的进程运行,此时它才能访问用户空间,也只有在此时它才会映射用户空间的内存。

     创建了工作项之后,在适当的时候可以通过下面的两种方式来提交工作项给工作者线程,通常我们使用的工作队列和工作者线程都是系统初始化时候默认创建的。


      工作队列的调度运行

        schedule_work(&work);

        &work马上就会被调度,一旦其所在的处理器上的工作者线程被唤醒,它就会被执行。

        schedule_delayed_work(&delay_work,delay);

        &delay_work指向的delay_work直到delay指定的时钟节拍用完以后才会执行。

     eg:

        schedule_delayed_work(&kpd_backlight_work,msecs_to_jiffies(300));

     

     默认工作队列和工作者线程创建过程

     系统默认的工作队列名称是:keventd_wq,默认的工作者线程叫:events/n,这里的n是处理器的编号,每个处理器对应一个线程。比如,单处理器的系统只有events/0这样一个线程。而双处理器的系统就会多一个events/1线程。

     默认的工作者线程会从多个地方得到被推后的工作。许多内核驱动程序都把它们的下半部交给默认的工作者线程去做。除非一个驱动程序或者子系统必须建立一个属于它自己的内核线程,否则最好使用默认线程。不过并不存在什么东西能够阻止代码创建属于自己的工作者线程。如果你需要在工作者线程中执行大量的处理操作,这样做或许会带来好处。处理器密集型和性能要求严格的任务会因为拥有自己的工作者线程而获得好处。

     默认的工作队列keventd_wq只有一个,但是其工作者线程在每一个cpu上都有。而标记为singlethread的工作者线程最存在于一个cpu上。

     关于默认工作队列keventd_wq和工作者线程events/n的建立在文件Kernel/kernel/workqueue.c中实现。

     Start_kernel()-->rest_init(),该函数中创建了两个内核线程kernel_init和kthreadd,这两个线程都和本文描述的部分有关系,先说说kernel_init。

     kernel_init()-->do_basic_setup()-->init_workqueues(),该函数中创建了上面提到的默认工作队列和工作者线程。

     init_workqueues()-->

     -->hotcpu_notifier(workqueue_cpu_callback,0);

     -->keventd_wq=create_workqueue("events");

     注册的cpu通知链cpu_chain上的回调函数是workqueue_cpu_callback(),raw_notifier_call_chain()函数用来调用cpu_chain上的所有回调函数。

     这里主要关注的是函数:create_workqueue("events");

     @kernel/include/linux/workqueue.h

     #define__create_workqueue(name,singlethread,freezeable,rt)/

     __create_workqueue_key((name),(singlethread),(freezeable),(rt),/NULL,NULL)

     #definecreate_workqueue(name)__create_workqueue((name),0,0,0)

     #definecreate_rt_workqueue(name)__create_workqueue((name),0,0,1)

     #definecreate_freezeable_workqueue(name)__create_workqueue((name),1,1,0)

     #definecreate_singlethread_workqueue(name)__create_workqueue((name),1,0,0)

     从宏__create_workqueue的参数可以看出,可以通过传递不同的参数:是否单cpu线程,是否可冻结,是否实时来创建不同类型的工作队列和工作者线程。

     work_struct工作项结构体定义:@kernel/include/linux/workqueue.h

     工作队列workqueue_struct结构体:@kernel/kernel/workqueue.c


    展开全文
  • linux工作队列 - workqueue总览

    万次阅读 2016-10-15 18:17:28
    workqueue归入中断子系统是由于和中断处理有密切关系,写博客重要在于整理自己的思绪,写的时候会把一些不懂的细节问题暴露出来,这样会把问题看的更透彻,workqueue的代码在...文章系列1.linux工作队列 - workqueue
  • linux工作队列 - workqueue_struct创建

    千次阅读 2016-10-16 19:27:20
    linux工作队列 - 把work_struct加入工作队列 4. linux工作队列 - work_struct被调用过程 1.创建workqueue代码分析 1.1整体代码分析 根据FLAG的不同,创建workqueue的API分好几种(见系列文章1说明),...
  • linux工作队列work queue

    2017-12-04 03:01:21
    内核中,触发中断后,在中断函数里使用mod_delayed_work延后100ms执行工作work,当work(即中断下半部)没执行完,又来了中断再次调用mod_delayed_work延后执行work,这时候正在执行的work会怎样,继续执行还是取消掉...
  • linux内核工作队列

    千次阅读 2017-12-09 12:45:42
    内核工作队列概述工作队列(workqueue)是另外一种将工作推后执行的形式,工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行,最重要的就是工作队列允许被重新调度...
  • Linux中的工作队列是将工作推后执行的一种方式,通常用在中断分层机制中,因为中断函数的原则是(1)快;(2)不能睡眠或等待;因此,在中断驱动程序中,引入工作队列实现中断的分层,硬件处理在中断函数中处理,...
  • linux内核工作队列demo

    2016-07-01 18:08:59
    很多博客都有深入分析内核队列工作原理,但是少有能够拿来直接运行的demo,这个demo亲测可用!
  • 最近项目组做xen底层,我已经被完爆无数遍了,关键在于对内核、驱动这块不熟悉,导致分析xen代码非常吃力。于是准备细细的将 几本 linux 书籍慢慢啃啃。 正好看到LINUX内核设计...书中一直强调 工作队列是可以休眠的
  • 工作队列(work queue)是Linux内核中将操作延期执行的一种机制。因为它们是通过守护进程在用户上下文执行,函数可以睡眠的时间,与内核是无关的。在内核版本2.5开发期间,设计了工作队列,用以替换此前的keventd机制...
  • 本文介绍了Linux操作系统内核工作队列的操作模式。
  • linux内核之工作队列

    2018-10-23 15:45:45
    在我的文章Linux内核:软中断、tasklet中,我们已经了解了中断底半部的两种实现方式,即软中断和tasklet微线程。但是这两种方式归根结底都是采用软中断机制的,其根本上还是在中断的上下文中执行,所以这也就要求了...
  • 把work_struct加入到工作队列workqueue的API在系列文章1有介绍,这些API虽然用法不一,但是最终都会调用__queue_work()函数来进行实际加入操作,比如API:queue_work_on:bool queue_work_on(int cpu, struct ...
  • linux工作队列

    2012-08-24 16:15:12
    Linux内核中,对下半部(或者说推后执行的工作)的处理方式有好几种,包括BH(bottom half),软中断,Tasklets和工作队列等等。在2.6内核中,大名鼎鼎的BH处理被废除,新增了更方便的工作队列工作队列的方便之...
  • linux工作队列机制详解

    千次阅读 2013-05-29 15:43:54
    Linux自从2.6.20之后,工作队列发生了一些变化,目前从网络上搜索的资料一般都是介绍老版本的工作队列,很少见到对新版本的介绍。本文对新老版本都做了简要概述,并分别提供了简单的实作案例。 ***************...
  • 主要介绍了Linux消息队列实现进程间通信实例详解的相关资料,需要的朋友可以参考下
  • linux c消息队列实现

    2019-04-02 14:06:53
    本资源包含四个文件,一个makefile,一个头文件,一个发送端一个接收端。发送端读取指定的文件,并且按照环境变量中设置的消息队列...两个程序都能在linux下 跑通,要编译 直接make就行。 只想要1积分,CSDN不让我改。
  • linux 工作队列之queue_work

    千次阅读 2013-03-26 09:47:45
    1、定时数据结构  struct work_struct work;  struct workqueue_struct *wq; 2、编写要在工作队列中被调用的函数,函数原形如下: ...3、创建一个专用的内核线程来执行提交到工作队列中的函数
  • linux 工作队列之schedule_work

    千次阅读 2013-03-25 11:08:59
    在许多情况下,设备驱动程序不需要有自己的工作队列。如果我们只是偶尔需要向队列中提交任务, 则一种更简单、更有效的办法是使用内核提供的共享的默认工作队列。但是,如果我们使用了这个默认 的工作队列,则应该...
  • linux 工作队列

    千次阅读 2011-10-22 13:24:55
    而与工作者线程相关的一个概念就是工作队列 , 或者叫 work queue. 工作队列的作用就是把工作推后 , 交由一个内核线程去执行 , 更直接的说就是如果您写了一个函数 , 而您现在不想马上执行它 , 您想在将来某个时刻去...
  • linux消息队列进行通信的 简单示例代码
  • linux工作队列编程

    千次阅读 2011-10-06 14:06:53
    linux工作队列(workqueue)是另外一种将工作推后执行的形式,它和软中断、tasklet 这两种下半部机制都有不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。...
  • linux 工作队列之schedule_delayed_work

    千次阅读 2013-03-25 16:34:21
    一、 schedule_delay_work ... 6、刷新默认工作队列(常跟cancle_delayed_work一起使用)  void flush_schedlue_work(void);                          
  • Linux内核v4.4中的多队列块设备 几年前,一个新的概念被合并到了 Linux 内核的块层中。 在此之前,每个块设备都有一个队列用于 IO 处理。 每个进程向队列中插入一个 IO 请求,块设备驱动程序从队列中提取一个请求。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 301,397
精华内容 120,558
关键字:

linux工作队列

linux 订阅