www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號精選 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]點擊上方"嵌入式開發(fā)圈" 記得關(guān)注我們哦! 一、Linux工作隊列與Linux小任務(wù)機制的區(qū)別 ???? ????工作隊列(work queue)是另外一種將工作推后執(zhí)行的形式,tasklet(小任務(wù)機制)有所不同。工作隊列可以把工作推后,交由一個內(nèi)核線程去執(zhí)行,也就是說,這個下半



點擊上方"嵌入式開發(fā)圈" 記得關(guān)注我們哦!
一、Linux工作隊列與Linux小任務(wù)機制的區(qū)別

    

    工作隊列(work queue)是另外一種將工作推后執(zhí)行的形式,tasklet(小任務(wù)機制)有所不同。工作隊列可以把工作推后,交由一個內(nèi)核線程去執(zhí)行,也就是說,這個下半部分可以在進程上下文中執(zhí)行。這樣,通過工作隊列執(zhí)行的代碼能占盡進程上下文的所有優(yōu)勢。最重要的就是工作隊列允許被重新調(diào)度甚至是睡眠。      

    那么,什么情況下使用工作隊列,什么情況下使用tasklet呢?如果推后執(zhí)行的任務(wù)需要睡眠,那么就選擇工作隊列;如果推后執(zhí)行的任務(wù)不需要睡眠,那么就選擇tasklet。另外,如果需要用一個可以重新調(diào)度的實體來執(zhí)行你的下半部處理,也應(yīng)該使用工作隊列。它是唯一能在進程上下文運行的下半部實現(xiàn)的機制,也只有它才可以睡眠。這意味著在需要獲得大量的內(nèi)存時、在需要獲取信號量時,在需要執(zhí)行阻塞式的I/O操作時,它都會非常有用。如果不需要用一個內(nèi)核線程來推后執(zhí)行工作,那么就考慮使用tasklet。    

    一般,不要輕易的去使用工作隊列,因為每當(dāng)創(chuàng)建一條工作隊列,內(nèi)核就會為這條工作隊列創(chuàng)建一條內(nèi)核線程。工作隊列位于進程上下文,與軟中斷,tasklet有所區(qū)別,工作隊列里允許延時,睡眠操作,而軟中斷,tasklet位于中斷上下文,不允許睡眠和延時操作。

二、使用Linux工作隊列

1、需要包含的頭文件

1#include <linux/workqueue.h>

2、工作隊列相關(guān)的數(shù)據(jù)結(jié)構(gòu)(各個版本內(nèi)核可能不同,這里用的是3.5)

 1//工作隊列結(jié)構(gòu)
2struct work_struct {
3    atomic_long_t data;
4    //鏈表處理
5    struct list_head entry;
6    //工作處理函數(shù)
7    work_func_t func;
8#ifdef CONFIG_LOCKDEP
9    struct lockdep_map lockdep_map;
10#endif
11};

3、操作工作隊列相關(guān)的API

 1創(chuàng)建一個隊列就會有一個內(nèi)核線程,一般不要輕易創(chuàng)建隊列
2位于進程上下文--->可以睡眠
3定義:
4    struct work_struct work;
5
6初始化:
7    INIT_WORK(struct work_struct *work, void (*func)(struct work_struct *work));
8
9定義并初始化:
10    DECLARE_WORK(name, void (*func)(struct work_struct *work));
11
12===========================================================
13
14調(diào)度:
15    int schedule_work(struct work_struct *work);
16    返回1成功, 0已經(jīng)添加在隊列上
17
18延遲調(diào)度:
19    int schedule_delayed_work(struct work_struct *work, unsigned long delay);
20
21===========================================================
22
23創(chuàng)建新隊列和新工作者線程:
24    struct workqueue_struct *create_workqueue(const char *name);
25
26調(diào)度指定隊列:
27    int queue_work(struct workqueue_struct *wq, struct work_struct *work);
28
29延遲調(diào)度指定隊列:
30    int queue_delayed_work(struct workqueue_struct *wq, 
31            struct work_struct *work, unsigned long delay
)
;
32銷毀隊列:
33    void destroy_workqueue(struct workqueue_struct *wq);

4、Demo實現(xiàn)(基于Tiny4412 Linux3.5內(nèi)核)

 1#include <linux/module.h>
2#include <linux/kernel.h>
3#include <linux/init.h>
4#include <linux/platform_device.h>
5#include <linux/fb.h>
6#include <linux/backlight.h>
7#include <linux/err.h>
8#include <linux/pwm.h>
9#include <linux/slab.h>
10#include <linux/miscdevice.h>
11#include <linux/delay.h>
12#include <linux/gpio.h>
13#include <mach/gpio.h>
14#include <plat/gpio-cfg.h>
15#include <linux/timer.h>  /*timer*/
16#include <asm/uaccess.h>  /*jiffies*/
17#include <linux/delay.h>
18#include <linux/interrupt.h>
19#include <linux/workqueue.h>
20struct tasklet_struct task_t ; 
21struct workqueue_struct *mywork ;
22//定義一個工作隊列結(jié)構(gòu)體
23struct work_struct work;
24static void task_fuc(unsigned long data)
25
{
26    if(in_interrupt()){
27             printk("%s in interrupt handle!\n",__FUNCTION__);
28        }
29}
30//工作隊列處理函數(shù)
31static void mywork_fuc(struct work_struct *work)
32
{
33    if(in_interrupt()){
34             printk("%s in interrupt handle!\n",__FUNCTION__);
35        }
36    msleep(2);
37    printk("%s in process handle!\n",__FUNCTION__);
38}
39
40static irqreturn_t irq_fuction(int irq, void *dev_id)
41
{    
42    tasklet_schedule(&task_t);
43    //調(diào)度工作
44    schedule_work(&work);
45    if(in_interrupt()){
46         printk("%s in interrupt handle!\n",__FUNCTION__);
47    }
48    printk("key_irq:%d\n",irq);
49    return IRQ_HANDLED ;
50}
51
52static int __init tiny4412_Key_irq_test_init(void) 
53
{
54    int err = 0 ;
55    int irq_num1 ;
56    int data_t = 100 ;
57    //創(chuàng)建新隊列和新工作者線程
58    mywork = create_workqueue("my work");
59    //初始化
60    INIT_WORK(&work,mywork_fuc);
61    //調(diào)度指定隊列
62    queue_work(mywork,&work);
63    tasklet_init(&task_t,task_fuc,data_t);
64    printk("irq_key init\n");
65    irq_num1 = gpio_to_irq(EXYNOS4_GPX3(2));
66    err = request_irq(irq_num1,irq_fuction,IRQF_TRIGGER_FALLING,"tiny4412_key1",(void *)"key1");
67    if(err != 0){
68        free_irq(irq_num1,(void *)"key1");
69        return -1 ;
70    }
71    return 0 ;
72}
73
74static void __exit tiny4412_Key_irq_test_exit(void) 
75
{
76    int irq_num1 ;
77    printk("irq_key exit\n");
78    irq_num1 = gpio_to_irq(EXYNOS4_GPX3(2));
79    //銷毀一條工作隊列
80    destroy_workqueue(mywork);
81    free_irq(irq_num1,(void *)"key1");
82}
83
84module_init(tiny4412_Key_irq_test_init);
85module_exit(tiny4412_Key_irq_test_exit);
86
87MODULE_LICENSE("GPL");
88MODULE_AUTHOR("YYX");
89MODULE_DESCRIPTION("Exynos4 KEY Driver");

將程序編譯完,將zImage下到板子上,重新啟動會看到內(nèi)核打印信息

    可以看到,當(dāng)我們按下按鍵的時候,進入外部中斷服務(wù)函數(shù),此時task_fuc先被調(diào)用,然后調(diào)用到mywork_fuc,并打印了mywork_fuc里面的信息,從這里我們用程序驗證了,工作隊列是位于進程上下文,而不是中斷上下文,和tasklet是有所區(qū)別的,下一節(jié)我們將會講一講tasklet(小任務(wù)機制)。


嵌入式干貨視頻推薦


商務(wù)合作

一、廣志創(chuàng)新科技相關(guān)產(chǎn)品





二、業(yè)務(wù)聯(lián)系






免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉
關(guān)閉