精华内容
下载资源
问答
  • 目标检测和跟踪的区别在于对于运动中变化目标的跟踪能力。设想这样一个场景:孙悟空在飞行过程中完成了一次变化(这里假设他变成了一只鸟),但这个变化并不是像西游记拍摄中有烟雾特效完成的,而就是通过身体结构...

    目标检测和跟踪的区别在于对于运动中变化目标的跟踪能力。设想这样一个场景:孙悟空在飞行过程中完成了一次变化(这里假设他变成了一只鸟),但这个变化并不是像西游记拍摄中有烟雾特效完成的,而就是通过身体结构发生渐变来完成的,这种情况下,检测器应该会在后续的检测任务中失败,因为设计好的检测器只是为了检测目标孙悟空的存在,孙悟空变身之后已经不存在这个目标,检测器是不会有火眼金睛继续检测到变化后的孙悟空的。

    但是,对于跟踪器就不一样了,跟踪目标,哪怕目标在跟踪过程中发生了巨大变化,这些都是跟踪器的本质能力。理想的跟踪器应该可以很好的跟上孙悟空渐变的整个过程,并且可以继续后面变身之后对鸟的跟踪。

    现在所谓的目标跟踪方法都是基于检测的(tracking by detection
    在很多人们设计的跟踪器的跟踪过程中,当目标出现遮挡或者运动出视野等情况时,直接使用检测器来对目标的位置进行重新检测。
    试想,如果目标在很长一段时间内一直出现被遮挡的状况,那么这一段时间内将会一直都是检测器在工作。
    理想的跟踪器应该不需要每一帧都暴力检测目标所在的位置,而是可以充分利用帧间信息,目标周围的环境信息,甚至根据周边环境推测得到的三维信息等,更加高效的确定目标所在的位置。
    理想的跟踪器应该可以对视频中的目标运动,周边环境有着更好的理解,这个理解不一定是和我们理解一致的语义理解,而是有助于跟踪任务的相关理解。

    目标检测和跟踪的区别还应在于对于相同目标不同实例的跟踪能力。设想一个目标检测器,其被设计用来检测行人,如果将其应用到马路场景上,检测器将会检测到马路上的大量行人,但如何让他只检测一个人呢?这好像是不可能的,因为其任务已经被设计为检测行人,其检测结果并不违背其设计初衷,而结果却并不是人们想要的。但这时跟踪器就完全不一样了,跟踪器可以初始化为跟踪行人,但在给跟踪器指定初始跟踪行人后,它将可以在后续的过程中只跟踪指定的行人,做到“弱水三千,而我只取一瓢饮”。

    比如在球场上我只想关注某一个球员、某几个球员的表现或是篮球的位置。

    目标跟踪更多考虑的是对目标的表达,跟踪过程中对目标表示的更新,跟踪中对周围环境变化信息、对时空信息的利用等等。正因如此,跟踪任务才即可被看作是生成式任务,也可以被看作为判别式任务,既可以通过深度学习的方法来暴力解决,也可以通过传统统计学、机器学习的方法来解决优化。但无论哪种解决方案,现在都没有在跟踪任务上取得突破性的成功。但这也恰恰使得跟踪这一视觉任务成为测试众多技术的理想平台。

    目标检测偏向于单帧下的物体定位识别,目标跟踪多帧之间的物体会有关联,重在跟踪和重识别,现在的跟踪算法有很大一部分是基于检测和滤波,目标检测会应用到目标跟踪中。

    假设视频中有两辆车,实时目标检测可以检测到有两辆车,而目标跟踪需要区分出这辆车是这辆车,另一辆车是另一辆车(re-ID的目的也是完成类似的工作)。

    简单来说:跟踪会比检测复杂一些.
    检测:目的是找到(或者静态或者动态);
    跟踪:目的是定位(动态)
    二者的联系是:
    (1) 跟踪是基于检测的,必须先定位目标,才能后续跟踪.
    (2) 如果将动态的检测(例如视频序列检测)分割成一定时间段内的静态检测(每一帧),那么用检测是可以实现类似跟踪的效果(伪跟踪,因为其实还是每一帧做检测).

    1.目标检测就是检测出一个图片或者一个视频中目标的位置(静态或者动态)如yolo检测目标

    2.目标追踪是给视频中第一帧目标以及它的位置,然后跟踪这个目标,以及预测它的轨迹,(如果出现一些遮挡,也可以根据轨迹来跟踪这个目标,假如是yolo检测出的目标,有时候还会出现丢帧的情况,如果用了跟踪算法,那么即使丢帧了,也可以跟住目标而不丢失,而且如果使用yolo,虽然给定了目标的位置,但是如果同一类的目标的话,你知道很多的目标的坐标,但是很难求出它们的轨迹。

    检测一般用到单帧的信息,主要是依据先验知识、或者显著等特性找到某些感兴趣的区域;
    而跟踪是已有目标的位置,在后续帧中找到最佳匹配位置,更侧重目标的匹配上;
    其实现在很多的跟踪算法是基于检测的,使得他们间联系更密切。

     

    此外,当前目标跟踪领域也存在一些问题亟待解决:

    部分表述及图示来源于知乎专栏--

    文中部分观点及说法有混淆和不清晰之处,欢迎指正~

    https://zhuanlan.zhihu.com/p/32826719

    https://zhuanlan.zhihu.com/p/104228012?utm_source=wechat_session

     

     

     

     


     

    展开全文
  • 目的通常是指行为主体根据自身需要,借助意识、观念中介作用,...任务目标的具体化。任务作为具体实践要求,回答了在某一时期、某一阶段人们应该做些什么事情。在马克思主义人学视野中,思想政治教育本原目

    目的通常是指行为主体根据自身的需要,借助意识、观念的中介作用,预先设想的行为目标和结果。作为观念形态,目的反映了人对客观事物的实践关系。人的实践活动以目的为依据,目的贯穿实践过程的始终。它是人们希望获得的最终结果,这个结果是整体性的,具有高度的概括性和抽象性。目标是个人、部门或整个组织所期望的成果,是目的和使命的具体化的表现,是在一定时期内所追求的最终成果和希望的未来状况。任务是目标的具体化。任务作为具体的实践要求,回答了在某一时期、某一阶段人们应该做些什么事情。在马克思主义人学视野中,思想政治教育的本原目的是促进人在社会中的生存和发展,思想政治教育的最高目的是促进人的自由全面发展,我国思想政治教育的现实目的是促进和谐的社会主体之生成。思想政治教育的目的,是指通过思想政治教育活动,在受教育者的思想和行为方面所期望达到的结果。换言之,思想政治教育的目的是人们根据一定的主客观条件对受教育者思想品德方面的质量的一种期望和规定。思想政治教育的目的是开展各项思想政治教育活动的依据和动力。思想政治教育的目的的实现是长期的、复杂的、艰巨的,可区分为若干阶段的过程。
    思想政治教育的目标是指思想政治教育者通过思想政治教育活动,期望思想政治教育对象在思想品德、政治素养、心理素质和行为习惯等方面所能达到的境界或预期结果。思想政治教育的目标不是头脑臆造的结果,它深深地植根于社会土壤之中。它取决于社会发展状况和需要,取决于现实的人全面发展提升自身的需要。以上可以看出,思想政治教育的目标是一个过程,是一个教育主体实现其目的的过程,这一过程体现的就是某一群体的阶段性教育结果和状态。关于思想政治教育的目的与思想政治教育的目标的关系,我们可以总结为一句话:思想政治教育目标是实现思想政治教育目的的具体途径,思想政治教育的目标以思想政治教育的目的为依据。
    高校思想政治教育的目标,是指高校根据社会发展的需要和大学生成才的要求,通过思想政治教育使大学生政治、思想、道德、心理、审美、法纪等素质在一定时期内达到预期效果。它是高校思想政治教育的出发点和归宿,是思想政治教育的首要核心问题,制约着思想政治教育的整个过程。正确的目标定位,不仅为有效实施思想政治教育明确了方向评估的依据,也为广大青年学生成才明确了可行性导向,在树立和落实科学发展观,全面构建社会主义和谐社会的时代背景下,进一步明确高校思想政治教育的目标定位,对于培养合格的社会主义事业建设者和接班人,推进两个文明建设乃至把建设有中国特色社会主义事业全面推向 21 世纪具有重要意义。

    展开全文
  • 一、中断处理tasklet(小任务)机制 中断服务程序一般都是在中断请求关闭条件下执行,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断时间太长,CPU就不能及时响应...

    转自:http://blog.csdn.net/sum_tw/article/details/53541148

    一、中断处理的tasklet(小任务)机制

    中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。因此,Linux内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。因此,内核把中断处理分为两部分:上半部(tophalf)和下半部(bottomhalf),上半部(就是中断服务程序)内核立即执行,而下半部(就是一些内核函数)留着稍后处理,

    首先,一个快速的“上半部”来处理硬件发出的请求,它必须在一个新的中断产生之前终止。通常,除了在设备和一些内存缓冲区(如果你的设备用到了DMA,就不止这些)之间移动或传送数据,确定硬件是否处于健全的状态之外,这一部分做的工作很少。

    下半部运行时是允许中断请求的,而上半部运行时是关中断的,这是二者之间的主要区别。

    但是,内核到底什时候执行下半部,以何种方式组织下半部?这就是我们要讨论的下半部实现机制,这种机制在内核的演变过程中不断得到改进,在以前的内核中,这个机制叫做bottomhalf(简称bh),在2.4以后的版本中有了新的发展和改进,改进的目标使下半部可以在多处理机上并行执行,并有助于驱动程序的开发者进行驱动程序的开发。下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。


    小任务机制    

    这里的小任务是指对要推迟执行的函数进行组织的一种机制数据结构为tasklet_struct,每个结构代表一个独立的小任务,其定义如下:

    structtasklet_struct {
    structtasklet_struct *next;         /*指向链表中的下一个结构*/
              unsignedlong state;                /* 小任务的状态*/
              atomic_tcount;        /* 引用计数器*/
              void(*func) (unsigned long);                /* 要调用的函数*/
              unsignedlong data;                 /* 传递给函数的参数*/
    };
    结构中的func域就是下半部中要推迟执行的函数,data是它唯一的参数。
    State域的取值为TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任务已被调度,正准备投入运行,TASKLET_STATE_RUN表示小任务正在运行。TASKLET_STATE_RUN只有在多处理器系统上才使用,单处理器系统什么时候都清楚一个小任务是不是正在运行(它要么就是当前正在执行的代码,要么不是)。
    Count域是小任务的引用计数器。如果它不为0,则小任务被禁止,不允许执行;只有当它为零,小任务才被激活,并且在被设置为挂起时,小任务才能够执行。
    1. 声明和使用小任务大多数情况下,为了控制一个寻常的硬件设备,小任务机制是实现下半部的最佳选择。小任务可以动态创建,使用方便,执行起来也比较快。
    我们既可以静态地创建小任务,也可以动态地创建它。选择那种方式取决于到底是想要对小任务进行直接引用还是一个间接引用。如果准备静态地创建一个小任务(也就是对它直接引用),使用下面两个宏中的一个:
    DECLARE_TASKLET(name,func, data)
    DECLARE_TASKLET_DISABLED(name,func, data)
    这两个宏都能根据给定的名字静态地创建一个tasklet_struct结构。当该小任务被调度以后,给定的函数func会被执行,它的参数由data给出。这两个宏之间的区别在于引用计数器的初始值设置不同。第一个宏把创建的小任务的引用计数器设置为0,因此,该小任务处于激活状态。另一个把引用计数器设置为1,所以该小任务处于禁止状态。例如:
    DECLARE_TASKLET(my_tasklet,my_tasklet_handler, dev);
    这行代码其实等价于
    structtasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),
                                                            tasklet_handler,dev};
    这样就创建了一个名为my_tasklet的小任务,其处理程序为tasklet_handler,并且已被激活。当处理程序被调用的时候,dev就会被传递给它。
    2.  编写自己的小任务处理程序小任务处理程序必须符合如下的函数类型:
    voidtasklet_handler(unsigned long data)
    由于小任务不能睡眠,因此不能在小任务中使用信号量或者其它产生阻塞的函数。但是小任务运行时可以响应中断。
    3. 调度自己的小任务通过调用tasklet_schedule()函数并传递给它相应的tasklt_struct指针,该小任务就会被调度以便适当的时候执行:
    tasklet_schedule(&my_tasklet);        /*把my_tasklet标记为挂起 */
    在小任务被调度以后,只要有机会它就会尽可能早的运行。在它还没有得到运行机会之前,如果一个相同的小任务又被调度了,那么它仍然只会运行一次。
            可以调用tasklet_disable()函数来禁止某个指定的小任务。如果该小任务当前正在执行,这个函数会等到它执行完毕再返回。调用tasklet_enable()函数可以激活一个小任务,如果希望把以DECLARE_TASKLET_DISABLED()创建的小任务激活,也得调用这个函数,如:
    tasklet_disable(&my_tasklet);        /*小任务现在被禁止,这个小任务不能运行*/
    tasklet_enable(&my_tasklet);        /*  小任务现在被激活*/
    也可以调用tasklet_kill()函数从挂起的队列中去掉一个小任务。该函数的参数是一个指向某个小任务的tasklet_struct的长指针。在小任务重新调度它自身的时候,从挂起的队列中移去已调度的小任务会很有用。这个函数首先等待该小任务执行完毕,然后再将它移去。
    4.tasklet的简单用法
        下面是tasklet的一个简单应用,以模块的形成加载。

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/kdev_t.h>
    #include <linux/cdev.h>
    #include <linux/kernel.h>
    #include <linux/interrupt.h>

    static struct  t asklet_struct my_tasklet;

    static void tasklet_handler (unsigned long d ata)
    {
            printk(KERN_ALERT,"tasklet_handler is running./n");
    }

    static int __init test_init(void)
    {
            tasklet_init(&my_tasklet,tasklet_handler,0);         tasklet_schedule(&my_tasklet);         return0; } static  void __exit test_exit(void) {         tasklet_kill(&tasklet);         printk(KERN_ALERT,"test_exit is running./n"); } MODULE_LICENSE("GPL"); module_init(test_init); module_exit(test_exit);

    从这个例子可以看出,所谓的小任务机制是为下半部函数的执行提供了一种执行机制,也就是说,推迟处理的事情是由tasklet_handler实现,何时执行,经由小任务机制封装后交给内核去处理。

     

    二、中断处理的工作队列机制

    工作队列(work queue)是另外一种将工作推后执行的形式,它和前面讨论的tasklet有所不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被重新调度甚至是睡眠。

    那么,什么情况下使用工作队列,什么情况下使用tasklet。如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后执行的任务不需要睡眠,那么就选择tasklet。另外,如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,它都会非常有用。如果不需要用一个内核线程来推后执行工作,那么就考虑使用tasklet。


    1. 工作、工作队列和工作者线程

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

    1. 表示工作的数据结构

    工作用<linux/workqueue.h>中定义的work_struct结构表示:

    struct work_struct{

    unsigned long pending; /* 这个工作正在等待处理吗?*/

    struct list_head entry; /* 连接所有工作的链表 */

    void (*func) (void *); /* 要执行的函数 */

    void *data; /* 传递给函数的参数 */

    void *wq_data; /* 内部使用 */

    struct timer_list timer; /* 延迟的工作队列所用到的定时器 */

    };

    这些结构被连接成链表。当一个工作者线程被唤醒时,它会执行它的链表上的所有工作。工作被执行完毕,它就将相应的work_struct对象从链表上移去。当链表上不再有对象的时候,它就会继续休眠。

    3. 创建推后的工作

    要使用工作队列,首先要做的是创建一些需要推后完成的工作。可以通过DECLARE_WORK在编译时静态地建该结构:

    DECLARE_WORK(name, void (*func) (void *), void *data);

    这样就会静态地创建一个名为name,待执行函数为func,参数为data的work_struct结构。

    同样,也可以在运行时通过指针创建一个工作:

    INIT_WORK(struct work_struct *work, woid(*func) (void *), void *data);

    这会动态地初始化一个由work指向的工作。

    4. 工作队列中待执行的函数

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

    void work_handler(void *data)

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

    5. 对工作进行调度

    现在工作已经被创建,我们可以调度它了。想要把给定工作的待处理函数提交给缺省的events工作线程,只需调用

    schedule_work(&work);

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

    有时候并不希望工作马上就被执行,而是希望它经过一段延迟以后再执行。在这种情况下,可以调度它在指定的时间执行:

    schedule_delayed_work(&work, delay);

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

    6. 工作队列的简单应用

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/workqueue.h>

    static struct workqueue_struct *queue = NULL;
    static struct work_struct work;

    static void work_handler(struct work_struct *data)
    {
            printk(KERN_ALERT "work handler function./n");
    }

    static int __init test_init(void)
    {
            queue = create_singlethread_workqueue("helloworld"); /*创建一个单线程的工作队列*/
            if (!queue)
                    goto err;

            INIT_WORK(&work, work_handler);
            schedule_work(&work);

            return 0;
    err:
            return -1;
    } static void __exit test_exit(void) {         destroy_workqueue(queue); } MODULE_LICENSE("GPL"); module_init(test_init); module_exit(test_exit);

    版权声明:本文为博主原创文章,转载请标明出处。http://blog.csdn.net/sum_tw

    转载于:https://www.cnblogs.com/sky-heaven/p/7921782.html

    展开全文
  • 面试题之小任务与工作队列的区别

    千次阅读 2016-12-09 16:41:48
    一、中断处理tasklet(小任务)机制 中断服务程序一般都是在中断请求关闭条件下执行,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断时间太长,CPU就不能及时响应...

    一、中断处理的tasklet(小任务)机制

    中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。因此,Linux内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。因此,内核把中断处理分为两部分:上半部(tophalf)和下半部(bottomhalf),上半部(就是中断服务程序)内核立即执行,而下半部(就是一些内核函数)留着稍后处理,

    首先,一个快速的“上半部”来处理硬件发出的请求,它必须在一个新的中断产生之前终止。通常,除了在设备和一些内存缓冲区(如果你的设备用到了DMA,就不止这些)之间移动或传送数据,确定硬件是否处于健全的状态之外,这一部分做的工作很少。

    下半部运行时是允许中断请求的,而上半部运行时是关中断的,这是二者之间的主要区别。

    但是,内核到底什时候执行下半部,以何种方式组织下半部?这就是我们要讨论的下半部实现机制,这种机制在内核的演变过程中不断得到改进,在以前的内核中,这个机制叫做bottomhalf(简称bh),在2.4以后的版本中有了新的发展和改进,改进的目标使下半部可以在多处理机上并行执行,并有助于驱动程序的开发者进行驱动程序的开发。下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。


    小任务机制    

    这里的小任务是指对要推迟执行的函数进行组织的一种机制数据结构tasklet_struct,每个结构代表一个独立的小任务,其定义如下:

    structtasklet_struct {
    structtasklet_struct *next;         /*指向链表中的下一个结构*/
              unsignedlong state;                /* 小任务的状态*/
              atomic_tcount;        /* 引用计数器*/
              void(*func) (unsigned long);                /* 要调用的函数*/
              unsignedlong data;                 /* 传递给函数的参数*/
    };
    结构中的func域就是下半部中要推迟执行的函数,data是它唯一的参数。
    State域的取值为TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任务已被调度,正准备投入运行,TASKLET_STATE_RUN表示小任务正在运行。TASKLET_STATE_RUN只有在多处理器系统上才使用,单处理器系统什么时候都清楚一个小任务是不是正在运行(它要么就是当前正在执行的代码,要么不是)。
    Count域是小任务的引用计数器。如果它不为0,则小任务被禁止,不允许执行;只有当它为零,小任务才被激活,并且在被设置为挂起时,小任务才能够执行。
    1. 声明和使用小任务大多数情况下,为了控制一个寻常的硬件设备,小任务机制是实现下半部的最佳选择。小任务可以动态创建,使用方便,执行起来也比较快。
    我们既可以静态地创建小任务,也可以动态地创建它。选择那种方式取决于到底是想要对小任务进行直接引用还是一个间接引用。如果准备静态地创建一个小任务(也就是对它直接引用),使用下面两个宏中的一个:
    DECLARE_TASKLET(name,func, data)
    DECLARE_TASKLET_DISABLED(name,func, data)
    这两个宏都能根据给定的名字静态地创建一个tasklet_struct结构。当该小任务被调度以后,给定的函数func会被执行,它的参数由data给出。这两个宏之间的区别在于引用计数器的初始值设置不同。第一个宏把创建的小任务的引用计数器设置为0,因此,该小任务处于激活状态。另一个把引用计数器设置为1,所以该小任务处于禁止状态。例如:
    DECLARE_TASKLET(my_tasklet,my_tasklet_handler, dev);
    这行代码其实等价于
    structtasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),
                                                            tasklet_handler,dev};
    这样就创建了一个名为my_tasklet的小任务,其处理程序为tasklet_handler,并且已被激活。当处理程序被调用的时候,dev就会被传递给它。
    2.  编写自己的小任务处理程序小任务处理程序必须符合如下的函数类型:
    voidtasklet_handler(unsigned long data)
    由于小任务不能睡眠,因此不能在小任务中使用信号量或者其它产生阻塞的函数。但是小任务运行时可以响应中断。
    3. 调度自己的小任务通过调用tasklet_schedule()函数并传递给它相应的tasklt_struct指针,该小任务就会被调度以便适当的时候执行:
    tasklet_schedule(&my_tasklet);        /*把my_tasklet标记为挂起 */
    在小任务被调度以后,只要有机会它就会尽可能早的运行。在它还没有得到运行机会之前,如果一个相同的小任务又被调度了,那么它仍然只会运行一次。
            可以调用tasklet_disable()函数来禁止某个指定的小任务。如果该小任务当前正在执行,这个函数会等到它执行完毕再返回。调用tasklet_enable()函数可以激活一个小任务,如果希望把以DECLARE_TASKLET_DISABLED()创建的小任务激活,也得调用这个函数,如:
    tasklet_disable(&my_tasklet);        /*小任务现在被禁止,这个小任务不能运行*/
    tasklet_enable(&my_tasklet);        /*  小任务现在被激活*/
    也可以调用tasklet_kill()函数从挂起的队列中去掉一个小任务。该函数的参数是一个指向某个小任务的tasklet_struct的长指针。在小任务重新调度它自身的时候,从挂起的队列中移去已调度的小任务会很有用。这个函数首先等待该小任务执行完毕,然后再将它移去。
    4.tasklet的简单用法
        下面是tasklet的一个简单应用,以模块的形成加载。

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/kdev_t.h>
    #include <linux/cdev.h>
    #include <linux/kernel.h>
    #include <linux/interrupt.h>

    static struct  t asklet_struct my_tasklet;

    static void tasklet_handler (unsigned long d ata)
    {
            printk(KERN_ALERT,"tasklet_handler is running./n");
    }

    static int __init test_init(void)
    {
            tasklet_init(&my_tasklet,tasklet_handler,0);
            tasklet_schedule(&my_tasklet);
            return0;
    }

    static  void __exit test_exit(void)
    {
            tasklet_kill(&tasklet);
            printk(KERN_ALERT,"test_exit is running./n");
    }
    MODULE_LICENSE("GPL");

    module_init(test_init);
    module_exit(test_exit);

    从这个例子可以看出,所谓的小任务机制是为下半部函数的执行提供了一种执行机制,也就是说,推迟处理的事情是由tasklet_handler实现,何时执行,经由小任务机制封装后交给内核去处理。

     

    二、中断处理的工作队列机制

    工作队列(work queue)是另外一种将工作推后执行的形式,它和前面讨论的tasklet有所不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被重新调度甚至是睡眠。

    那么,什么情况下使用工作队列,什么情况下使用tasklet。如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后执行的任务不需要睡眠,那么就选择tasklet。另外,如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,它都会非常有用。如果不需要用一个内核线程来推后执行工作,那么就考虑使用tasklet。


    1. 工作、工作队列和工作者线程

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

    1. 表示工作的数据结构

    工作用<linux/workqueue.h>中定义的work_struct结构表示:

    struct work_struct{

    unsigned long pending; /* 这个工作正在等待处理吗?*/

    struct list_head entry; /* 连接所有工作的链表 */

    void (*func) (void *); /* 要执行的函数 */

    void *data; /* 传递给函数的参数 */

    void *wq_data; /* 内部使用 */

    struct timer_list timer; /* 延迟的工作队列所用到的定时器 */

    };

    这些结构被连接成链表。当一个工作者线程被唤醒时,它会执行它的链表上的所有工作。工作被执行完毕,它就将相应的work_struct对象从链表上移去。当链表上不再有对象的时候,它就会继续休眠。

    3. 创建推后的工作

    要使用工作队列,首先要做的是创建一些需要推后完成的工作。可以通过DECLARE_WORK在编译时静态地建该结构:

    DECLARE_WORK(name, void (*func) (void *), void *data);

    这样就会静态地创建一个名为name,待执行函数为func,参数为data的work_struct结构。

    同样,也可以在运行时通过指针创建一个工作:

    INIT_WORK(struct work_struct *work, woid(*func) (void *), void *data);

    这会动态地初始化一个由work指向的工作。

    4. 工作队列中待执行的函数

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

    void work_handler(void *data)

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

    5. 对工作进行调度

    现在工作已经被创建,我们可以调度它了。想要把给定工作的待处理函数提交给缺省的events工作线程,只需调用

    schedule_work(&work);

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

    有时候并不希望工作马上就被执行,而是希望它经过一段延迟以后再执行。在这种情况下,可以调度它在指定的时间执行:

    schedule_delayed_work(&work, delay);

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

    6. 工作队列的简单应用

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/workqueue.h>

    static struct workqueue_struct *queue = NULL;
    static struct work_struct work;

    static void work_handler(struct work_struct *data)
    {
            printk
    (KERN_ALERT "work handler function./n");
    }

    static int __init test_init(void)
    {
            
    queue = create_singlethread_workqueue("helloworld"); /*创建一个单线程的工作队列*/
            
    if (!queue)
                    
    goto err;

            INIT_WORK
    (&work, work_handler);
            schedule_work
    (&work);

            
    return 0;
    err
    :
            
    return -1;
    }

    static void __exit test_exit(void)
    {
            destroy_workqueue
    (queue);
    }
    MODULE_LICENSE
    ("GPL");
    module_init
    (test_init);
    module_exit
    (test_exit);

    展开全文
  • 下图(来源于网络)展示了上述四个概念之间的区别。 目前,图像分类是进行深度学习研究学习的基本任务,其主要是在已知类别数量的情况下,通过输入一张图片,来判断图片所属类别。 目标定位则是在图像分类的...
  • 分类和回归的区别可以从多个角度进行描述,本文采用最简单的一个角度:输出变量的类型。 定量输出称为回归,或者说是连续变量预测; 定性输出称为分类,或者说是离散变量预测。 举个例子: 预测明天的气温是多少度,...
  • 任务与函数

    2016-11-16 14:39:00
    1.任务与函数的区别 函数 任务 函数能调用另一个函数,但不能调用另一个任务 任务能调用另一个任务,也能调用另一个函数 函数总是在仿真时刻0就开始执行 任务可以在非零时刻仿真 ...
  • 集群分布式的区别

    2017-11-25 23:28:54
    分布式和集群都是需要有很多节点服务器通过网络协同工作完成整体的任务目标。 不同点 分布式是指将业务系统进行拆分,即分布式每一个节点都是实现不同功能。而集群每个节点做是同一件事情。 举例说明 如下图...
  • 引入监督学习的任务就是学习一个模型(或者得到一个目标函数),应用这一模型,对给定输入预测相应输出。这一模型一般形式为一个决策函数Y=f(X),或者条件概率分布P(Y|X)。监督学习方法又可以分为生成方法...
  • 码农三哥愿大家每日分享java开发过程中笔记和互联网人工智能技术文章,愿你我互交流,共同成长!...区别就在于输入数据是文本,图片,还是其他数据类型。开始之前先允许我做一个简单划重点,以便大家对...
  • 并发并行的区别

    千次阅读 2019-04-23 21:07:34
    并发(concurrency)和并行(parallellism): 并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在...所以并发编程的目标是充分利用处理器每一个核,以达到最高处理性能。 并行(parallel...
  • MPSMRP的区别

    万次阅读 2012-06-26 11:26:22
    MPSMRP的区别 1、MPS是MRP的直接目的,MPS体现的是净需求,MRP运算出来的作业计划和采购计划的目的就是完成MPS提出的任务,从而达到企业外部市场需求的目标。 2、MPS主要针对有独立需求计划而言,它是整个计划...
  • 概要设计详细设计的区别

    千次阅读 2019-09-26 10:35:15
    #概要设计详细设计的区别如下: 1、概要设计的主要任务是把需求分析得到的系统扩展用例图转换为软件结构和数据结构。设计软件结构的具体任务是:将一个复杂系统按功能进行模块划分、建立模块的层次结构及调用关系...
  • 在经历了5月7日一次小小波折之后,8日下午13点30分,我国新一代载人飞船试验船顺利返回东风着陆场,此次发射和...新飞船返回舱开伞降落 从新一代载人飞船试验船返航画面来看,它之前神舟飞船重返地球不太...
  • mavenant的区别

    千次阅读 2018-09-09 17:38:12
    Ant和Maven都是基于Java构建(build)工具。理论上来说,有些类似于(Unix)C中make ,但没有make缺陷。...3.没有生命周期,必须定义目标及其实现的任务序列 4.没有集成依赖管理 Maven特...
  •  分布式和集群都是需要有很多节点服务器通过网络协同工作完成整体的任务目标。 不同点:  分布式是指将业务系统进行拆分,即分布式每一个节点都是实现不同功能。而集群每个节点做是同一件事情。   图说...
  • JSONXML的区别比较

    2020-07-17 11:20:34
    虽然这两种格式设计目标并不相同,但它们常常用于同一个任务,也就是数据交换中。XML 和 JSON 文档都很完善,且都同时具有人类可读性和机器可读性。这两种格式并没有哪一个比另一个更强,只是各自适用领域不用...
  • 如果详细进行区别: 测试计划定义就是一个叙述了预定测试活动范围、途径、资源及进度安排文档。它确认了测试项、被测特征、测试任务、人员安排,以及任何偶发事件风险。 内容: 产品概述、测试方法、测试...
  • 测试计划测试方案的关系对比...间进度安排,提出对各项任务的评估、风险分析 和需求管理 描述需要测试的特性、测试的方法、测试环境的 规划、测试工具的设计和选择、测试用例的设计 方法、测试代码的设计方案。 ...
  • startActivityForResultstartActivity不同之处在于: 1、startActivity( ) 仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity( )。 2、startActivityForResult( ) 可以一次性完成这...
  • UXPM职能区别

    千次阅读 2016-03-18 10:20:03
    UX设计师——基于对用户行为认知同时永远牢记商业目标,在界面中呈现公司愿景。UX设计师聚焦于评估用户体验,讨论出一个可行问题解决方案,并将团队讨论结果设计实现。 产品经理——是痴迷于在最佳时机...
  • BPELXPDL定位区别

    千次阅读 2008-07-03 13:07:00
    根据最近对几个BPEL产品研究,根据以前对XPDL了解,分析了BPELXPDL在业务目标方面主要区别。定义、缩略语:l XPDL:The XML Process Definition Language。l BPEL:Business Process Execution Language...
  • 机器学习中分类聚类本质区别

    千次阅读 2018-05-17 17:05:00
    在我们的生活中,我们常常没有过多的去区分这两个概念,觉得聚类就是分类,分类也差不多就是聚类,下面,我们就具体来研究下分类聚类之间在数据挖掘中本质的区别。分类分类有如下几种说法,但表达的意思是相同的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 459
精华内容 183
关键字:

任务目标与目标任务的区别