KRTS中Task的使用

KRTS中Task的使用



任务

多任务模块可在 内核层用户层 上执行任务。在 内核层 上,任务调度是优先级控制的。因此,一个任务永远不会被优先级较低的另一个任务打断。另一方面,优先级较低的任务可能会被优先级较高的任务打断。在内核级别实现的抢占式调度,如下所述的用户级别的协作调度的限制。

用户层 任务通过协同调度进行管理。因此,正在运行的任务只能在同步点(如事件或信号量)处切换。另一种选择是,正在运行的任务自行处理,以便让调度程序有机会安排另一个任务。如果任务不是自行处理或在同步对象处等待,则只要任务正在运行,就无法安排其他任务。用户级任务的一个优点是可以进行调试,并且处理起来比标准 Windows 线程要容易得多。

另一种选择是将任务分配给不同的 CPU。这在 多处理器 下是受支持。任务、中断和计时器可以分配给多个 CPU 内核。使用"专用"实时模式,可以专门使用 CPU 内核,而不受 Windows 影响。因此,可以存档极高的实时功能。有关详细信息,请参阅 设置目标处理器

这些任务由 255 个级别控制。请注意,每个级别可以执行无限数量的任务。调度器每个级别都使用循环算法运行,即任务被组织在一个优先级队列中(FIFO,先进先出)。如果任务运行到结束或被切换,则队列中具有相同优先级的下一个任务将获得执行时间。调度器会考虑每个 CPU 内核的优先级,例如,优先级较低的任务可以在特定的 CPU 内核上运行,而不会被另一个 CPU 内核上优先级较高的任务打断。

为了同步任务,提供了同步对象 信号互斥锁事件

任务可以在请求任务信号量时继承优先级。此外,还支持动态优先级,即根据更改其他任务的优先级,可以阻止或启动任务。

与 Windows 线程相比,可以使用函数 KS_triggerTask 轻松重新计划任务。在执行的代码结束时,任务可以再次重新触发自身。

有一些有趣的 实时 功能与任务结合使用。计时器作为任务执行,多个计时器可以同时控制多个任务。调度程序通过优先级控制代码的执行。

对于定时器,不使用基础频率,即将定时器编程到下一个所需的时间点。同时,时钟和计时器保持同步 - 不会发生漂移。系统会自动为每个硬件选择最佳定时器源。

实时计时器支持高达 100 kHz 的频率,每个计时器都在每个 CPU 上独立处理。循环定时器和一次性定时器可以使用。

结合任务,_步骤编程_的概念可能很有趣。该应用程序分为几个已完成的步骤。每个步骤都分配给一个任务。如果完成一项任务,则对计时器进行编程以启动下一个任务。

实时计时器的另一个功能是在流程上调整计时器,例如将计时器周期增加少量。

最后但并非最不重要的一点是,可以同时启动多个定时器。这可以通过函数 KS_startTimerDelayed 来完成。可以提供绝对启动时间或相对启动延迟。要同时启动多个定时器,可以为多个定时器设置绝对启动时间。

创建任务

要创建任务,可以使用函数 KS_createTask。参数需要回调句柄和优先级。使用标志"KSF_DONT_START",在调用 KS_triggerTask 之前,任务不会启动。

处理任务

任务操作包括触发、挂起、恢复、等待、休眠、退出和终止。
对于任务操作,函数 KS_triggerTaskKS_suspendTaskKS_resumeTaskKS_yieldTaskKS_sleepTaskKS_exitTaskKS_killTask 有规定。函数"KS_triggerTask"无法中断正在运行的任务。任务将从状态 休眠暂停 |休眠 触发。

此外,任务可以暂停并再次恢复。一个任务可以让位于同一优先级的另一个任务。如果不存在具有相同优先级的任务,则使用刚刚准备就绪的最高任务。

调用函数 ‘KS_sleepTask’ 调度器将在给定的时间段内延迟任务。

有两种方法可以结束任务:退出和终止。如果调用了 KS_exitTask,则任务会立即退出,但可以再次触发。函数"KS_killTask"最终会终止任务。无法再次触发该任务。

使用函数 KS_getTaskState,可以查询任务状态之一(休眠准备运行等待暂停)。要设置设置任务的堆栈大小。

设定优先级

函数 KS_setTaskPrio 设置任务优先级。从 1…31 开始的优先级称为空闲,从 32…255 开始的优先级称为正常。具有空闲优先级的任务可能会被Kithara系统任务中断。如果使用"专用"实时模式,并且至少为 Windows 保留一个核心,否则可以忽略此设置。

如果使用所有系统时间的高优先级任务,例如Windows无法获得最短时间,则将注册BSOD!解决这个问题的一种方法是使用空闲的优先级。不需要所有系统时间的循环任务也没问题。最后但并非最不重要的一点是,可以使用几乎没有延迟的 步骤编程

设置目标处理器并获取当前上下文信息

使用函数 KS_setTargetProcessor,可以设置当前线程或任务的目标处理器。调用此函数后在任务或线程内创建的每个资源(例如中断、回调、计时器、任务等)都将被分配给指定的逻辑处理器。

这样一来,计算负载甚至不能被划分为不同的任务,而且还可以分配给不同的CPU内核。此选项适用于普通 CPU 和"专用"CPU。

目标处理器的计数从第一个共享Windows CPU 开始,然后是"专用"CPU。在 Windows 中配置共享Windows CPU 和"专用"CPU 的数量(请参阅 设置专用 CPU)。

如果任务或线程正在运行,则可以使用函数 KS_getCurrentProcessor 查询其当前使用的处理器号。使用标志"KSF_NUM_PROCESSORS",可以只获取实时处理器的数量。

要获取有关当前执行上下文的信息,可以使用函数 KS_getCurrentContext。它提供结构 KSContextInformation。在当前级别旁边,将传递有关任务的信息,如任务句柄、优先级、当前逻辑处理器编号和堆栈信息。

同步任务

如果多个任务共享一个公共资源,则通常需要任务同步(读取器/写入器问题)。提供了三个同步对象:事件、互斥锁 和 信号。事件互斥锁已经在另一个教程中处理过。让我们看一下信号量。

信号量只能由实时任务请求。与 互斥锁 相比,信号量没有所有权,即信号量可以被任何正在运行的任务解锁。

创建信号量

可以使用函数 KS_createSemaphore 创建信号量。作为参数,需要最大计数和初始计数。最大计数指定了在信号量阻塞之前所需的请求数(要共享的资源)。最大计数必须大于 1。使用初始计数,可以设置起始值。该值必须小于或等于最大计数。

请求或释放信号量

信号量有两个操作:请求和释放。要执行这些操作,可以使用函数 KS_requestSemaphoreKS_releaseSemaphore。要请求信号量,需要信号量句柄和超时。超时以 100 ns 为单位给出。

如果信号量是空闲的,则内部计数器将减少 1,任务将继续运行。否则,任务将被阻塞,直到信号量再次空闲。对于请求信号量,_优先继承_的概念开始发挥作用。如果任务已请求信号量的优先级低于请求信号量的任务,则请求任务将从已请求信号量的任务中继承较高的优先级。因此,请求任务可以以继承的更高优先级运行。

要释放信号量,只需要一个信号量句柄。函数"KS_releaseSemaphore"增加内部计数器,直到达到最大计数。如果其他任务正在等待请求信号量,则优先级最高的任务将设置为 准备

删除信号量

要删除信号量并释放其所有资源,必须使用函数 KS_removeSemaphore

移除任务

要删除任务并释放其所有资源,必须使用函数 KS_removeTask

必须删除使用 KS_createTask 创建的每个任务。对于用 KS_killTask 终止的任务也是如此。

任务状态和过渡

下图显示了所有任务状态(休眠准备运行等待暂停)以及每个函数导致的转换。

在这里插入图片描述

特别说明

Task 中执行的代码,最高允许使用 C++20 的标准,支持几乎所有的STL库,也包括像SML这种三方库的使用。

示例代码

核心代码:

    // 设置任务专用的CPU
    KSError error = KS_setTargetProcessor(kernel_data_ptr_->task_cpu,KSF_NO_FLAGS);
    if (error != KS_OK) { KS_printK("KS_setTargetProcessor failed!\n"); }

    error = KS_createCallBack(&kernel_data_ptr_->task_callback_handle, TaskCallback, nullptr, KSF_DIRECT_EXEC | KSF_SAVE_FPU, 0);
    if (error != KS_OK) { return error; }

    error = KS_setTaskStackSize(0x100000, KSF_NO_FLAGS);
    if (error != KS_OK) { return error; }

    error = KS_createTask(&kernel_data_ptr_->task_handle, kernel_data_ptr_->task_callback_handle, 172, KSF_CUSTOM_STACK_SIZE);
    if (error != KS_OK) { return error; }

在任务回调中的代码,支持C++20 的标准语法,标准库,以及部分第三方的库。

// 这是实时任务将运行的函数,并对执行 Task 操作。只有实时任务才应调用 Task 函数。
KSError __stdcall TaskCallback(void * /*pArgs*/, void * /*pContext*/)
{
    TaskHandle task_handle;

    // 处理循环,此循环仅在发出中止信号时停止。
    while (true)
    {
        // 等待图像接收或停止的通知。
        if (kernel_data_ptr_->abort != 0) { break; }

        task_handle.SetCount(1);

        // 填充图像信息到共享内存中
        kernel_data_ptr_->count = task_handle.Count();

        KS_sleepTask(REFRESH_TIME*10*1000);
    }
    return KS_OK;
}

完整代码示例:
请查阅task_stl分支

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值