zephyr笔记 2.1.5 工作队列线程

我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总

1 前言

工作队列是一个内核对象,它使用专用线程以先进先出的方式处理工作项目。 通过调用工作项目指定的功能来处理每个工作项目。 ISR或高优先级线程通常使用工作队列来将非紧急处理卸载到较低优先级的线程,因此不会影响对时间敏感的处理事务。

http://docs.zephyrproject.org/kernel/threads/workqueues.html

2 概念

可以定义任何数量的工作队列。 每个工作队列都由其内存地址引用。

工作队列具有以下关键属性:

  • 已添加但尚未处理的工作项目队列。
  • 处理队列中工作项的线程。线程的优先级是可配置的,可以根据需要进行合作或抢占。

在使用之前,工作队列必须初始化。这将其队列设置为空,并生成工作队列的线程。

2.1 工作项目生命周期

可以定义任何数量的工作项目。每个工作项都由其内存地址引用。

工作项目具有以下关键属性:

  • 处理函数,它是在处理工作项时由工作队列的线程执行的函数。 这个函数接受一个参数,它是工作项目本身的地址。
  • 挂起标志,内核用它来表示工作项目当前是工作队列队列的成员。
  • 一个队列链接,内核用它将待处理的工作项链接到工作队列队列中的下一个待处理工作项。

工作项目在使用之前必须进行初始化。这会记录工作项的处理函数并将其标记为未挂起。

工作项目可以通过ISR或线程提交给工作队列。提交工作项目会将工作项目附加到工作队列的队列中。一旦工作队列的线程处理了队列中的所有前面的工作项,线程将从队列中移除一个待处理的工作项并调用工作项的处理函数。根据工作队列线程的调度优先级以及队列中其他项所需的工作,可能会快速处理未完成的工作项,或者可能会延长队列中的工作时间。

处理函数可以利用线程可用的任何内核API。但是,必须小心使用可能阻塞的操作(例如,采取信号量),因为在处理函数完成执行之前,工作队列无法处理队列中的后续工作项。

如果不需要,可以忽略传递给处理函数的单个参数。如果处理函数需要关于它要执行的工作的附加信息,则工作项可以嵌入到更大的数据结构中。处理函数然后可以使用参数值来计算封闭数据结构的地址,从而获得对它所需的附加信息的访问。

工作项目通常被初始化一次,然后在需要执行工作时提交给特定的工作队列。如果ISR或线程尝试提交已处于待处理状态的工作项,则工作项不受影响;工作项目仍保留在工作队列中的当前位置,并且工作仅执行一次。

允许处理函数将其工作项参数重新提交给工作队列,因为此时工作项不再处于等待状态。这允许处理程序分阶段执行工作,而不会过度延迟对工作队​​列队列中其他工作项的处理。

重要:只有在挂起的工作项目由工作队列线程处理之后,才能做更改。 这意味着一个工作项目在挂起时不能重新初始化。 此外,在处理函数完成执行之前,工作项处理函数执行其工作所需的任何附加信息都不得更改。

2.2 延迟工作

ISR或线程可能需要安排一个工作项目,该工作项目只能在指定的时间段后处理,而不是立即处理。 这可以通过将延迟工作项目提交给工作队列而不是标准工作项目来完成。

延迟工作项目是标准工作项目的基础上,增加了以下附加属性:

  • 指定在工作项目实际提交给工作队列的队列之前,所需等待的时间延迟。
  • 识别工作项目将被提交到工作队列的工作队列指示符。

虽然使用了不同的内核API,但延迟工作项目将以类似于标准工作项目的方式初始化并提交给工作队列。当发出提交请求时,内核会启动超时机制,该机制会在指定的延迟过去后触发。一旦发生超时,内核会将延迟的工作项目提交给指定的工作队列,在那里它将保持挂起状态,直到以标准方式处理为止。

一个ISR或一个线程可能会取消它已提交的延迟工作项目,只要工作项目的超时仍在倒计时。工作项目的超时将中止,并且不执行指定的工作。

一旦超时已过,试图取消延迟的工作项目对工作项目没有影响;工作项目在工作队列队列中保持挂起状态,除非工作项目已被工作队列的线程移除和处理。因此,一旦工作项目的超时过期,工作项目总是由工作队列处理并且不能被取消。

2.3 系统工作队列

内核定义了一个称为系统工作队列的工作队列,可用于需要工作队列支持的任何应用程序或内核代码。 系统工作队列是可选的,只有在应用程序使用它时才存在。

重要:只有在无法将新工作项目提交给系统工作队列时才应定义其他工作队列,因为每个新工作队列都会占用大量内存。 如果工作项目不可能与现有系统工作队列工作项目并存而没有不可接受的影响,那么新的工作队列就是合理的; 例如,如果新工作项目执行的阻塞操作会延迟其他系统工作队列处理至不可接受的程度。

3 操作

3.1 定义1个工作队列

使用 struct k_work_q 类型的变量定义工作队列。 通过定义线程使用的堆栈区域然后调用 k_work_q_start() 来初始化工作队列。 堆栈区域必须使用 K_THREAD_STACK_DEFINE 定义,以确保它在内存中正确设置。

以下代码定义并初始化一个工作队列。

#define MY_STACK_SIZE 512
#define MY_PRIORITY 5

K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);

struct k_work_q my_work_q;

k_work_q_start(&my_work_q, my_stack_area,
               K_THREAD_STACK_SIZEOF(my_stack_area), MY_PRIORITY);

3.2 提交工作项目

工作项目是使用 struct k_work 类型的变量定义的。 它必须通过调用 k_work_init() 来初始化。

初始化的工作项可以通过调用 k_work_submit() 或者通过调用 k_work_submit_to_queue() 来提交给系统工作队列。

以下代码演示了ISR如何卸载将错误消息打印到系统工作队列。 请注意,如果ISR在仍处于挂起状态时尝试重新提交工作项目,则工作项目保持不变,并且不会打印相关的错误消息。

struct device_info {
    struct k_work work;
    char name[16]
} my_device;

void my_isr(void *arg)
{
    ...
    if (error detected) {
        k_work_submit(&my_device.work);
    }
    ...
}

void print_error(struct k_work *item)
{
    struct device_info *the_device =
        CONTAINER_OF(item, struct device_info, work);
    printk("Got error on device %s\n", the_device->name);
}

/* initialize name info for a device */
strcpy(my_device.name, "FOO_dev");

/* initialize work item for printing device's error messages */
k_work_init(&my_device.work, print_error);

/* install my_isr() as interrupt handler for the device (not shown) */
...

3.3 提交延迟的工作项目

使用 struct k_delayed_work 类型的变量定义延迟工作项目。 然后它必须通过调用k_delayed_work_init() 来初始化。

可以通过调用 k_delayed_work_submit() 或通过调用 k_delayed_work_submit_to_queue() 将初始化的延迟工作项目提交给系统工作队列。 通过调用 k_delayed_work_cancel() 可以取消已提交但尚未被工作队列使用的延迟工作项目。

4 建议用法

使用系统工作队列将复杂的中断相关处理从ISR推迟到协作线程。 这允许中断相关处理迅速完成,而不会影响系统响应后续中断的能力,并且不需要应用程序定义额外的线程来执行处理。

5 配置选项

  • CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE
  • CONFIG_SYSTEM_WORKQUEUE_PRIORITY

6 API

k_work_q_start()
k_work_init()
k_work_submit()
k_work_submit_to_queue()
k_delayed_work_init()
k_delayed_work_submit()
k_delayed_work_submit_to_queue()
k_delayed_work_cancel()
k_work_pending()

End


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值