工作队列-31

Posted 杨斌并

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工作队列-31相关的知识,希望对你有一定的参考价值。

工作队列

工作队列的基础概念

什么是工作队列?

工作队列(workqueue)是实现中断下文的机制之一,是一种将工作推后执行的形式。

那工作队列和我们tasklet,机制的不同点

tasklet 也是实现中断下文的机制。他们俩个最主要的区别是tasklet,不能休眠,而工作队列是可以休眠的。所以,tasklet可以用来处理比较耗时间的事情,而工作队列可以处理非常复杂并且更耗时间的事情。

工作队列(workqueue)的工作原理

​ Linux系统在启动期间会创建内核线程,该线程创建以后就处于sleep状态,然后这个线程会一直去队列里面读,看看有没有任务,如果有就执行,如果没有就休眠。工作队列的实现机制实际上是非常复杂的,初学阶段只需要了解这些基本概念接口。

共享工作队列有什么有缺点呢?

不需要自己创建,但是如果前面的工作比较耗时间,就会影响后面的工作。

自定义工作队列有什么优缺点呢?

需要自己创建,系统开销大。优点是不会受到其他工作的影响。(因为这个流水线就是专门加工这一种零件的。)

工作队列相关API(#include <linux/workqueue.h>)

尽管工作队列的实现机制非常复杂,但是我们使用工作队列其实就是在这个流水线上添加自己的物料,然后等待执行即可。
一个具体的工作(类比就是流水线上的物料)我们使用结构体 work_struct来描述的,定义在Linux\\worklqueue.h里面。
所以我们使用工作队列的第一步就是先定义个工作队列。

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

在这个结构体里面我们只需要关注func这个成员就可以了,他是是一个函数指针,因为我们要把我们需要完成的工作写在这个函数里面。

  • 宏DECLARE_WORK

原型:

#define DECLARE_WORK(n, f)

作用:

  • 静态定义并且初始化工作队列。

  • 宏INIT_WORK

原型:

#define INIT_WORK(_work,_func)

作用:

动态定义并初始化工作结构

参数:

  • work: 工作队列的地址
  • func:工作函数

举例

struct work_struct test;

INIT_WORK(&test,func)
//相当于
DECLARE_WORK(&test,func)

  • schedule_work

原型:

int schedule_work(struct work_struct *work);

作用:

调度工作,把 work_struct挂到CPU相关的工作结构队列链表上,等待工作者线程处理。

参数:

  • work工作队列地址;
  • 需要注意的是,如果调度完工作,并不会马上执行,只是加到了共享的工作队列里面去,等轮到他才会执行。
  • 如果我们多次调用相同的任务,假如上一次的任务还没有处理完成,那么多次调度相同的任务是无效的

代码

  • driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/workqueue.h>

int gpio_num;
int irq = 0;
struct device_node *test_device_node;
struct property *test_node_property;
//struct tasklet_struct key_tesk;
struct work_struct key_tesk;

struct of_device_id of_match_table[] = {

    {.compatible = "test_keys"},
    {}

};

irq_handler_t test_key(int irq, void *args){

    printk("test_key start \\n");

    //tasklet_schedule(&key_tesk);
    schedule_work(&key_tesk);
    printk("test_key end \\n");

    return IRQ_HANDLED;

}

void test(unsigned long data){
    int i = 100;
    while (i--)
    {
        printk("task_key long time is %d \\n", i);
    }
    
}

int beep_probe(struct platform_device *pdev){

    int ret = 0;


    printk("beep_probe 匹配成功了 \\n");
    test_device_node = of_find_node_by_path("/test_key");
    if (test_device_node == NULL)
    {
        printk("of_find_node_by_path is error \\n");
        return -1;
    }
    
    gpio_num = of_get_named_gpio(test_device_node, "touch-gpio", 0);
    if (gpio_num < 0)
    {
        printk("of_get_named_gpio is error \\n");
        return -1;
    }
    
    gpio_direction_input(gpio_num);

    
    //irq = gpio_to_irq(gpio_num);

    irq = irq_of_parse_and_map(test_device_node, 0);

    printk("irq is %d \\n", irq);

    ret = request_irq(irq, test_key, IRQF_TRIGGER_RISING, "test_key", NULL);
    if (ret < 0)
    {
        printk("request_irq is error \\n");
        return ret;
    }

    //tasklet_init(&key_tesk, test, 100);
    INIT_WORK(&key_tesk, test);

    return 0;
}

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

const struct platform_device_id  beep_idtable = {
    .name = "test_keys"
};

struct platform_driver beep_device =
{
    .probe = beep_probe,
    .remove = beep_remove,
    .driver = {
        .name = "123",
        .owner = THIS_MODULE,
        .of_match_table = of_match_table
    },
    .id_table = &beep_idtable
};

static int beep_driver_init(void){
    printk(KERN_EMERG "hello world enter \\n");
    int ret = 0;
    ret = platform_driver_register(&beep_device);
    if (ret < 0)
    {
        printk("platform_driver_register 失败\\n");
    }

    printk("platform_driver_register ok\\n");
    
    return 0;
}

static void beep_driver_exit(void){
    printk(KERN_EMERG "hello world exit! \\n");
    tasklet_kill(&key_tesk);
    free_irq(irq, NULL);
    platform_driver_unregister(&beep_device);
}

module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LIYU");

设备树的代码
将下面的代码注释

	touch-gpio = <&gpio1 20 IRQ_TYPE_EDGE_RISING>;
	interrupt-parent = <&gpio1>;
    interrupts = <20 IRQ_TYPE_LEVEL_LOW>;

然后在根节点中添加下面的代码

test_key {
		compatible = "test_keys";
		pinctrl-names = "default";
		pinctrl-0 = <&i2c1_xfer>;
        reg = <0x38>;
		touch-gpio = <&gpio1 20 IRQ_TYPE_EDGE_RISING>;
		interrupt-parent = <&gpio1>;
        interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
	
	};

以上是关于工作队列-31的主要内容,如果未能解决你的问题,请参考以下文章

# Java 常用代码片段

来自dispatch_async全局崩溃的C函数调用,但在主队列上工作

RabbitMQ:工作队列模式

onRequestPermissionsResult 在片段中不起作用

片段中的 startActivityForResult 不工作

如何通过代码设置片段标签?