Linux 工作队列和等待队列

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

queue_work

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

@ workqueue_struct:指定的workqueue指针

@work_struct:具体任务对象指针



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

等待队列

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

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

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

 

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

扫描二维码关注公众号,回复: 2366785 查看本文章

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

 

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

等待队列头是一个类型为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操作时,它都会非常有用


对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就可以把中断,任务,设备名等全部囊括进来
我理解就差不多是这样的。希望大叔级任务指出不正之处。

猜你喜欢

转载自blog.csdn.net/m0_37321987/article/details/79650088