5

我正在研究一种使用网守任务来访问共享资源的设计。我现在拥有的基本设计是看门人任务从中接收的单个队列以及将请求放入其中的多个任务。

这是一个内存有限的系统,我使用的是 FreeRTOS(Cortex M3 端口)。

问题如下:异步处理这些请求相当简单。请求任务将其请求排队并继续其业务、轮询、处理或等待其他事件。为了同步处理这些请求,我需要一种机制来阻止请求任务,这样一旦请求被处理,网守就可以唤醒调用该请求的任务。

我能想到的最简单的设计是在每个请求中包含一个信号量,但考虑到内存限制和 FreeRTOS 中相当大的信号量,这是不切实际的。

我想出的是使用任务挂起和任务恢复功能手动阻止任务,将句柄传递给网守,它可以在请求完成时恢复任务。但是,暂停/恢复存在一些问题,我真的很想避免它们。无论任务被其他调用挂起多少次,一个恢复调用都会唤醒一个任务,这可能会产生不良行为。

一些简单的伪 C 来演示挂起/恢复方法。

void gatekeeper_blocking_request(void)
{
     put_request_in_queue(request);
     task_suspend(this_task);
}

void gatekeeper_request_complete_callback(request)
{
     task_resume(request->task);
}

我计划在此期间使用的一种解决方法是使用异步调用并在每个请求任务中完全实现阻塞。当操作完成时,网守将执行提供的回调,然后可以发布到任务的主队列或特定的信号量,或任何需要的东西。对请求进行阻塞调用本质上是一种便利功能,因此每个请求任务都不需要实现这一点。

伪 C 来演示特定于任务的阻塞,但这需要在每个任务中实现。

void requesting_task(void)
{
     while(1)
     {
         gatekeeper_async_request(callback);
         pend_on_sempahore(sem);
     }
}

void callback(request)
{
     post_to_semaphore(sem);
}

也许最好的解决方案就是不在网关守卫和 API 中实现阻塞,并强制每个任务处理它。不过,这会增加每个任务流程的复杂性,我希望我可以避免它。在大多数情况下,所有调用都希望阻塞,直到操作完成。

是否有一些我遗漏的结构,或者只是我可以用谷歌搜索的这类问题的更好术语?我在搜索中没有遇到过这样的事情。

附加说明- 看门人任务的两个原因:

  1. 需要大的堆栈空间。与其将这个要求添加到每个任务中,网关守卫可以拥有一个包含所有所需内存的堆栈。

  2. CPU 中的资源并不总是可访问的。它不仅同步 CPU 中的任务,还同步 CPU 外的任务。

4

2 回答 2

2

使用互斥锁并使网守成为子例程而不是任务。

于 2010-11-09T18:04:42.047 回答
2

自从我发布这个问题已经六年了,我一直在努力让同步按照我的需要工作。使用的操作系统结构存在一些可怕的滥用。我已经考虑过更新此代码,即使它有效,也不要那么滥用,因此我研究了更优雅的方法来处理这个问题。在过去的六年里,FreeRTOS 还添加了许多功能,我相信其中一个功能提供了一种轻量级的方法来完成同样的事情。

直接任务通知

重新审视我最初提出的方法:

void gatekeeper_blocking_request(void)
{
     put_request_in_queue(request);
     task_suspend(this_task);
}

void gatekeeper_request_complete_callback(request)
{
     task_resume(request->task);
}

避免使用此方法的原因是因为 FreeRTOS 任务挂起/恢复调用不计数,因此多个挂起调用将被单个恢复调用否定。当时,应用程序正在使用挂起/恢复功能,因此这是一个真正的可能性。

从 FreeRTOS 8.2.0 开始,直接任务通知本质上提供了一个轻量级的内置任务二进制信号量。当向任务发送通知时,可以设置通知值。该通知将处于休眠状态,直到被通知的任务调用某个变体,xTaskNotifyWait()或者如果它已经进行了这样的调用,它将被唤醒。

上面的代码,可以稍微修改如下:

 void gatekeeper_blocking_request(void)
 {
      put_request_in_queue(request);
      xTaskNotifyWait( ... );
 }

 void gatekeeper_request_complete_callback(request)
 {
      xTaskNotify( ... );
 }

这仍然不是一种理想的方法,就好像任务通知在其他地方使用一样,您可能会遇到与挂起/恢复相同的问题,其中任务被不同于预期的源唤醒。鉴于,对我来说,这是一个新功能,它可能会在修改后的代码中发挥作用。

于 2016-08-30T19:06:24.803 回答