Linux内核实践之工作队列_bullbat的博客-CSDN博客_内核工作队列
这个资料讲到了队列的两种使用方法
域名停靠 这个资料中讲到了任务的移除
参见中断子系统中的下半部内容
工作队列实际是由一个内核线程去维护和执行队列上的任务的。
当系统启动后,内核为每一个cpu都创建一个工作队列(即缺省的工作队列),每个工作队列由一个内核线程去维护,线程的名字叫[kworker/0]表示cpu 0 的线程,
[kworker/1]表示cpu1的线程。所以有几个cpu就可以看到几个[kworker/xxx].
当系统缺省的工作队列负载太大的时候,我们可以选择自己创建一个工作队列。
在老内核中,每创建一个工作队列,就要为每一个cpu新建一个内核线程。这样当你创建的工作队列很多的时候会消耗很多的调度资源,包括内存。。,线程名称就是你的创建工作队列的时候
填入的name,如果是多cpu,比如3个,当你创建这个工作队列以后,你就会看到有[name/0],[name/1],[name/2]这样3个内核线程。这样非常不利于并发。
域名停靠 这个资料中讲到了任务的移除
参见中断子系统中的下半部内容
工作队列实际是由一个内核线程去维护和执行队列上的任务的。
当系统启动后,内核为每一个cpu都创建一个工作队列(即缺省的工作队列),每个工作队列由一个内核线程去维护,线程的名字叫[kworker/0]表示cpu 0 的线程,
[kworker/1]表示cpu1的线程。所以有几个cpu就可以看到几个[kworker/xxx].
当系统缺省的工作队列负载太大的时候,我们可以选择自己创建一个工作队列。
在老内核中,每创建一个工作队列,就要为每一个cpu新建一个内核线程。这样当你创建的工作队列很多的时候会消耗很多的调度资源,包括内存。。,线程名称就是你的创建工作队列的时候
填入的name,如果是多cpu,比如3个,当你创建这个工作队列以后,你就会看到有[name/0],[name/1],[name/2]这样3个内核线程。这样非常不利于并发。
以下内容摘自:中断服务下半部之工作队列详解 - arm-linux - 博客园
这么做会在每个处理器上都创建一个工作者线程,所以只有在你明确了必须要靠自己的一套线程来提高性能的情况下,再创建自己的工作队列。创建一个新的任务队列和与之相关的工作者线程,只需调用一个简单的函数:create_workqueue。这个函数会创建所有的工作者线程(系统中的每个处理器都有一个)并且做好 所有开始处理工作之前的准备工作。name参数用于该内核线程的命名。对于具体的线程会更加CPU号添加上序号。create_workqueue和create_singlethread_workqueue都是创建一个工作队列,但是差别在于create_singlethread_workqueue可以指定为此工作队列只创建一个内核线程,这样可以节省 资源,无需发挥SMP的并行处理优势。
新内核中,这种每创建一个工作队列就要为每一个cpu都创建一个内核线程的做法得到的改变。但是系统启动的时候任然会为每个cpu创建一个缺省的工作队列,并各自由一个内核线程去维护。
当我们要创建一个新的工作队列的时候,只在某个cpu上创建一个内核线程去维护这个工作队列。
正确的使用队列以及在工作队列中传参
一。使用内核缺省的工作队列:
1.struct work_struct work; //定义一个work结构体,即队列项
2.任务函数:static void demo_task_monitor(struct work_struct *
task_work)
{
可以传入自己的私有结构体
- struct xxx*test = container_of(work, struct xxx, task_work);
}
3.将任务结构体初始化,绑定任务
INIT_WORK(&work,demo_task_monitor);
4.将任务加入缺省队列,同时开启任务:此时任务开始被调度执行
schedule_work(&work);
static inline bool schedule_work(struct work_struct *work)
{
return queue_work(system_wq, work);//可以看到内部仍然是一个queue_work,只不过将对队列项加在了系统默认的内核队列中了
}
5.从工作队列中删除这个任务
cancel_work_sync(&work);//remove task from work queue
6.再次执行这个任务:
schedule_work(&work);//其实是对queue_work的一次封装,指定了内核的缺省队列
二。自己创建工作队列,并且将任务加入自己的工作队列。
struct workqueue_struct *workqueue; //定义一个工作队列结构体
struct work_struct work;//定义一个任务结构体
1.与使用内核缺省的工作队列不同,这种方式首先要自己先建立一个工作队列
workqueue = create_workqueue("task_xx");
2.初始化一个任务
INIT_WORK(&work, demo_task);//将任务结构体初始化,绑定任务
3,加入自己创建的队列,并开始调度
queue_work(dev->workqueue, &dev->work);
4,从工作队列中删除这个任务
cancel_work_sync(&work);//remove task from work queue
5,销毁这个工作队列:
destroy_workqueue(struct workqueue_struct *wq);