linux 工作队列(workqueue)——非常详细易懂

2024-02-05 08:58

本文主要是介绍linux 工作队列(workqueue)——非常详细易懂,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/liuxd3000/article/details/7700247

在处理内核相关工作中, 我们经常看到工作队列(workqueue)的身影. 本文描述何为 linux workqueue.本文基于 2.6.32 的内核, 此时的工作队列还不是 cmwq.

为什么使用 workqueue?

在内核代码中, 经常希望延缓部分工作到将来某个时间执行, 这样做的原因很多, 比如

.在持有锁时做大量(或者说费时的)工作不合适.
.希望将工作聚集以获取批处理的性能.
.调用了一个可能导致睡眠的函数使得在此时执行新调度非常不合适.
...
内核中提供了许多机制来提供延迟执行, 使用最多则是 workqueue.

.如中断的下半部处理可延迟中断上下文中的部分工作;
.定时器可指定延迟一定时间后执行某工作;
.workqueue 则允许在进程上下文环境下延迟执行;
.内核中曾短暂出现过的慢工作机制 (slow work mechanism);
.异步函数调用(asynchronous function calls);
.各种私有实现的线程池;
...
术语

workqueue: 所有工作项(需要被执行的工作)被排列于该队列.
worker thread: 是一个用于执行 workqueue 中各个工作项的内核线程, 当 workqueue 中没有工作项时, 该线程将变为 idle 状态.
single threaded(ST): worker thread 的表现形式之一, 在系统范围内, 只有一个 worker thread 为 workqueue 服务.
multi threaded(MT): worker thread 的表现形式之一, 在多 CPU 系统上每个 CPU 上都有一个 worker thread 为 workqueue 服务.
使用步骤


创建 workqueue(如果使用内核默认的 workqueue, 此步骤略过).
创建工作项 work_struct.
向 workqueue 提交工作项.
工作项


数据结构(略有调整):


struct work_struct {
    atomic_long_t data;
    struct list_head entry;
    work_func_t func;
    struct lockdep_map lockdep_map;
};
struct delayed_work {
    struct work_struct work;
    struct timer_list timer;
};
静态地创建工作项:

DECLARE_WORK(n, f)
DECLARE_DELAYED_WORK(n, f)
动态地创建工作项:

INIT_WORK(struct work_struct work, work_func_t func); 
PREPARE_WORK(struct work_struct work, work_func_t func); 
INIT_DELAYED_WORK(struct delayed_work work, work_func_t func); 
PREPARE_DELAYED_WORK(struct delayed_work work, work_func_t func); 
内核默认的 workqueue

查阅源码可知, 内核默认的全局 workqueue 应为:

// 定义
static struct workqueue_struct *keventd_wq __read_mostly;


// 初始化
...
keventd_wq = create_workqueue("events"); // MT worker thread 模式.
...


// 确认对应的内核线程数目, 应等于 CPU 核数
$ lscpu
Architecture:          x86_64
CPU(s):                3
Thread(s) per core:    1
$ ps aux | grep "events"
root         9  0.0  0.0      0     0 ?        S    Feb09   1:15 [events/0]
root        10  0.0  0.0      0     0 ?        S    Feb09   0:59 [events/1]
root        11  0.0  0.0      0     0 ?        S    Feb09   0:59 [events/2]
工作项加入 keventd_wq 由下面两个函数之一完成:


int schedule_work(struct work_struct *work)
{
    return queue_work(keventd_wq, work);
}
int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
{
    return queue_delayed_work(keventd_wq, dwork, delay);
}
用户自定义的 workqueue

创建 workqueue:

create_singlethread_workqueue(name) // 仅对应一个内核线程
create_workqueue(name) // 对应多个内核线程, 同上文.
向 workqueue 中提交工作项:

int queue_work(workqueue_t *queue, work_t *work); 
int queue_delayed_work(workqueue_t *queue, work_t *work, unsigned long delay); 
取消 workqueue 中挂起的工作项以及释放 workqueue 此处略过.

工作队列的优点

使用简单.
执行在进程上下文, 从而可以睡眠, 被调度和抢占.
在多核环境下使用也非常友好.
example

#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>

static struct workqueue_struct *queue = NULL;
static struct work_struct work;

static void work_handler(struct work_struct *data)
{
    printk(KERN_ALERT "work handler for work_item in queue helloworkqueue\n");
    // workqueue 中的每个工作完成之后就被移除 workqueue.
    // 下面的语句会造成"死机", 原因可能是该 workqueue 占据了所有的 CPU 时间.
    // queue_work(queue, &work);
}

static int __init test_init(void)
{
    queue = create_singlethread_workqueue("helloworkqueue");
    if (!queue)
    {   
        goto err;
    }   
    INIT_WORK(&work, work_handler);
    queue_work(queue, &work);

    return 0;
err:
    return -1; 
}
static void __exit test_exit(void)
{
    destroy_workqueue(queue);
}

MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);
view rawworkqueue_example.cThis Gist brought to you by GitHub.
Makefile:

obj-m := wq.o
default:
    make -C /usr/src/linux-2.6.32.12-0.7 M=`pwd` modules


这篇关于linux 工作队列(workqueue)——非常详细易懂的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/680395

相关文章

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

Nginx中配置HTTP/2协议的详细指南

《Nginx中配置HTTP/2协议的详细指南》HTTP/2是HTTP协议的下一代版本,旨在提高性能、减少延迟并优化现代网络环境中的通信效率,本文将为大家介绍Nginx配置HTTP/2协议想详细步骤,需... 目录一、HTTP/2 协议概述1.HTTP/22. HTTP/2 的核心特性3. HTTP/2 的优

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Win11安装PostgreSQL数据库的两种方式详细步骤

《Win11安装PostgreSQL数据库的两种方式详细步骤》PostgreSQL是备受业界青睐的关系型数据库,尤其是在地理空间和移动领域,:本文主要介绍Win11安装PostgreSQL数据库的... 目录一、exe文件安装 (推荐)下载安装包1. 选择操作系统2. 跳转到EDB(PostgreSQL 的

Python3.6连接MySQL的详细步骤

《Python3.6连接MySQL的详细步骤》在现代Web开发和数据处理中,Python与数据库的交互是必不可少的一部分,MySQL作为最流行的开源关系型数据库管理系统之一,与Python的结合可以实... 目录环境准备安装python 3.6安装mysql安装pymysql库连接到MySQL建立连接执行S