北京SEO

Linux中的work queue

2019/10/10/17:47:20  阅读:1985  来源:谷歌SEO算法  标签: 夫唯SEO视频教程

工作队列(work queue)是Linux kernel中将工作推后执行的一种机制,这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠.

工作队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化,因此本文分成两个部分对2.6.20之前和之后的版本分别做介绍.

1、2.6.0~2.6.19

数据结构,代码如下:

  1. structwork_struct{
  2. unsignedlongpending;
  3. structlist_headentry;
  4. void(*func)(void*);
  5. void*data;
  6. void*wq_data;
  7. structtimer_listtimer;
  8. };

pending是用来记录工作是否已经挂在队列上;

entry是循环链表结构;

func作为函数指针,由用户实现;

data用来存储用户的私人数据,此数据即是func的参数;

wq_data一般用来指向工作者线程,工作者线程参考下文;

timer是推后执行的定时器。

work_struct的这些变量里,func和data是用户使用的,其他是内部变量,我们可以不用太过关心.

API:

1) INIT_WORK(_work, _func, _data)

初始化指定工作,目的是把用户指定的函数_func及_func需要的参数_data赋给work_struct的func及data变量.

2) int schedule_work(struct work_struct *work)

对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程,工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作.

3) int schedule_delayed_work(struct work_struct *work, unsigned long delay)

延迟执行工作,与schedule_work类似.

4) void flush_scheduled_work(void)

刷新缺省工作队列,此函数会一直等待,直到队列中的所有工作都被执行.

5) int cancel_delayed_work(struct work_struct *work)

flush_scheduled_work并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work.

以上均是采用缺省工作者线程来实现工作队列,其优点是简单易用,缺点是如果缺省工作队列负载太重,执行效率会很低,这就需要我们创建自己的工作者线程和工作队列.

API:

1) struct workqueue_struct *create_workqueue(const char *name)

创建新的工作队列和相应的工作者线程,name用于该内核线程的命名.

2) int queue_work(struct workqueue_struct *wq, struct work_struct *work)

类似于schedule_work,区别在于queue_work把给定工作提交给创建的工作队列wq而不是缺省队列.

3) int queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay)

延迟执行工作.

4) void flush_workqueue(struct workqueue_struct *wq)

刷新指定工作队列.

5) void destroy_workqueue(struct workqueue_struct *wq)

释放创建的工作队列.

下面一段代码可以看作一个简单的实作,代码如下:

  1. voidmy_func(void*data)
  2. {
  3. char*name=(char*)data;
  4. printk(KERN_INFO“Helloworld,mynameis%s!\n”,name);
  5. }
  6. structworkqueue_struct*my_wq=create_workqueue(“mywq”);
  7. structwork_structmy_work;
  8. INIT_WORK(&my_work,my_func,“Jack”);
  9. queue_work(my_wq,&my_work);
  10. destroy_workqueue(my_wq);
  11. //开源代码phpfensi.com

2、2.6.20~2.6.??

自2.6.20起,工作队列的数据结构发生了一些变化,使用时不能沿用旧的方法,数据结构,代码如下:

  1. typedefvoid(*work_func_t)(structwork_struct*work);
  2. structwork_struct{
  3. atomic_long_tdata;
  4. structlist_headentry;
  5. work_func_tfunc;
  6. };

与2.6.19之前的版本相比,work_struct瘦身不少,粗粗一看,entry和之前的版本相同,func和data发生了变化,另外并无其他的变量.

entry我们不去过问,这个和以前的版本完全相同,data的类型是atomic_long_t,这个类型从字面上看可以知道是一个原子类型,第一次看到这个变量时,很容易误认为和以前的data是同样的用法,只不过类型变了而已,其实不然,这里的data是之前版本的pending和wq_data的复合体,起到了以前的pending和wq_data的作用.

func的参数是一个work_struct指针,指向的数据就是定义func的work_struct.

看到这里,会有两个疑问,第一,如何把用户的数据作为参数传递给func呢?以前有void *data来作为参数,现在好像完全没有办法做到,第二,如何实现延迟工作?目前版本的work_struct并没有定义timer.

解决第一个问题,需要换一种思路,2.6.20版本之后使用工作队列需要把work_struct定义在用户的数据结构中,然后通过container_of来得到用户数据,具体用法可以参考稍后的实作.

对于第二个问题,新的工作队列把timer拿掉的用意是使得work_struct更加单纯,首先回忆一下之前版本,只有在需要延迟执行工作时才会用到timer,普通情况下timer是没有意义的,所以之前的做法在一定程度上有些浪费资源,所以新版本中,将timer从work_struct中拿掉,然后又定义了一个新的结构delayed_work用于处理延迟执行,代码如下:

  1. structdelayed_work{
  2. structwork_structwork;
  3. structtimer_listtimer;
  4. };

下面把API罗列一下,每个函数的解释可参考之前版本的介绍或者之后的实作.

1) INIT_WORK(struct work_struct *work, work_func_t func)

2) INIT_DELAYED_WORK(struct delayed_work *work, work_func_t func)

3) int schedule_work(struct work_struct *work)

4) int schedule_delayed_work(struct delayed_work *work, unsigned long delay)

5) struct workqueue_struct *create_workqueue(const char *name)

6) int queue_work(struct workqueue_struct *wq, struct work_struct *work)

7) int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay)

8) void flush_scheduled_work(void)

9) void flush_workqueue(struct workqueue_struct *wq)

10) int cancel_delayed_work(struct delayed_work *work)

11) void destroy_workqueue(struct workqueue_struct *wq)

其中,1), 2), 4) ,7)和以前略有区别,其他用法完全一样,实作,代码如下:

  1. structmy_struct_t{
  2. char*name;
  3. structwork_structmy_work;
  4. };
  5. voidmy_func(structwork_struct*work)
  6. {
  7. structmy_struct_t*my_name=container_of(work,structmy_struct_t,my_work);
  8. printk(KERN_INFO“Helloworld,mynameis%s!\n”,my_name->name);
  9. }
  10. structworkqueue_struct*my_wq=create_workqueue(“mywq”);
  11. structmy_struct_tmy_name;
  12. my_name.name=“Jack”;
  13. INIT_WORK(&(my_name.my_work),my_func);
  14. queue_work(my_wq,&my_work);
  15. destroy_workqueue(my_wq);

广告内容

Linux中的work queue Linux中的work queue Linux中的work queue

相关阅读

热门评论

Seven 绯闻SEO Seven 绯闻SEO

绯闻SEO,一个专注中小企业网站优化的SEO爱好者

总篇数179

精选文章

RMAN中catalog和nocatalog区别介绍 小技巧:为Linux下的文件分配多个权限 zimbra8.5.1安装第三方签名ssl证书的步骤 解决mysql不能远程连接数据库方法 windows服务器mysql增量备份批处理数据库 mysql中slow query log慢日志查询分析 JavaScript跨域问题总结 Linux下负载均衡软件LVS配置(VS/DR)教程 mysql中权限参数说明 MYSQL(错误1053)无法正常启动

SEO最新算法