当前位置:   article > 正文

linux工作队列应用实例_linux的队列

linux的队列

一、工作队列

linux实现中断下文的机制主要有4种:
1.软中断 2.tasklet 3.工作队列 4.线程化irq

本文主要介绍中断下文机制中的工作队列,工作队列与tasklet最大的区别就是tasklet不能休眠,工作队列可以休眠,所以tasklet多用来处理比较耗时间的任务,而工作队列可以处理非常复杂并且更耗时间的事情。

**实现原理:**工作队列的实现机制非常复杂,简单的来说就是,Linux系统在启动期间会创建内核线程,该线程创建以后就处于sleep状态,然后这个线程会一直去队列里面读,看看有没有任务,如果有就执行,没有就休眠。

**共享工作队列:**多个不同的程序共用,不需要自己创建,但如果前面的工作比较耗时的话,就会影响到后面的工作。

**自定义工作队列:**共享工作队列无法满足需要时,需要我们自己创建,其系统的开销大,优点是不会受到其他工作的影响。

二、内核提供的接口

内核源码路径:/include/linux/workqueue.h 定义了工作队列的结构体。

struct work_struct {
    atomic_long_t data;
    struct list_head entry;
    work_func_t func;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.1 宏DECLARE_WORK

#dedfine DECLARE_WORK(n,f);
  • 1

功能:静态定义并且初始化工作队列。

2.2 宏INIT_WORK:

#define INIT_WORK (_work,_func);
  • 1

功能:动态定义并且初始化工作队列。
参数介绍:
work:工作队列地址;
func:工作函数;

2.3 schedule_work函数;

int schedule_work(struct work_struct *work);
  • 1

功能:调度工作,把work_struct挂到cpu相关的工作队列链表上,等待工作者线程处理。
参数介绍:
work:工作队列地址。
在此,调度完工作,并不会马上执行,只是加到了共享队列里面去,等轮到时才会执行。
如果多次调用相同的任务,假如上一次的任务还没有完成,那么多次调度相同的任务是无效的。

三、实例代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/workqueue.h>


struct device_node *test_device_node;
struct property *test_node_property;
struct work_struct key_test;

int gpio_num;
int irq;

//中断上文函数
irq_handler_t test_key(int irq, void *args)
{
    printk("Start!\n");
    //唤醒工作队列
    schedule_work(&key_test);
    printk("End!\n");
    return IRQ_HANDLED;//接收到了准确的中断信号,并且做了相应正确的处理
}

//中断下文函数
void work_queue_test(unsigned long data)
{
    int i = 0;
    while(i<50){
        i++;
        printk("test_key is %d.\n",i);
    }
}

//探针函数,用于设备的初始化    
int dts_probe(struct platform_device *pdev)
{
    int ret = 0;
    printk("dts_probe matching ok!\n");

    //test_device_node = of_find_node_by_name(NULL,"test_key");//根据节点名字索引设备树节点
    
    test_device_node = of_find_node_by_path("/test_key");//根据据对路径索引设备树节点
    if(test_device_node == NULL){
        printk("Failture to find device node %s","test_key");
        return -1;
    }

    //获取gpio的编号
    gpio_num = of_get_named_gpio(test_device_node,"key-gpio",0);
    if(gpio_num < 0){
        printk("Failture to get gpio %s","key-gpio");
        return -1;
    }

    //设置gpio的方向
    gpio_direction_input(gpio_num);

    //irq = irq_of_parse_and_map(test_device_node,0);
    irq = gpio_to_irq(gpio_num);//同上一句代码,为gpio申请中断号
    printk("irq is %d\n",irq);
    
    //申请并注册中断资源
    ret = request_irq(irq,test_key,IRQF_TRIGGER_RISINNG,"test_key",NULL);
    if(ret < 0){
        printk("Failed to requst irq\n")
        return -1;
    }

    //初始化key_test这个工作队列,并且将work_queue_test添加进工作队列
    INIT_WORK(&key_test,work_queue_test);
    return 0;
    
}

int dts_remove(struct platform_device *pdev)
{
    printk("dts_remove!\n");
    return 0;
}

//根据设备名字匹配
const struct platform_device_id dts_idtable = {
    .name = "dts_test1"
}

//根据compatible匹配
const struct of_device_id of_match_table_test[] = {
    {.compatible = "led_keys"},
    {}
}

//初始化dts_driver结构体
struct platform_driver dts_driver = {
    .probe = dts_probe,
    .remove = dts_remove,
    .driver = {
        .ower = THIS_MODULE,
        .name = "dts_test2",
        .of_match_table = of_match_table_test
    },
    .id_table = &dts_idtable
};

//驱动初始化函数
static int dts_driver_init(void)
{
    int ret = 0;
    ret = platform_driver_register(&dts_driver);
    if(ret < 0){
        printk("platform driver register error\n");
        return ret;
    }
    printk("platform driver register of!\n");
    return 0;
}

//驱动卸载函数
static int dts_driver_exit(void)
{
    printk("dts_driver_exit!\n");
    free_irq(irq,NULL);
    platform_driver_unregister(&dts_driver);
}

//模块加载
module_init(dts_driver_init);
//模块卸载
module_exit(dts_driver_exit);
/*模块许可证声明,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,
 *会收到内核被污染“kernel tainted” 的警告 */
MODULE_LICENSE("GPL");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137

3.2 Makefile文件

obj-m += work_queue.o
KDIR:=/linux/linux-4.1.15
PWD?=$(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

当系统启动完成之后执行:

insmod work_queue
  • 1

加载该模块

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/601575
推荐阅读
相关标签
  

闽ICP备14008679号