通常情况下,我会通过以下内容解决此问题:
task = _taskProvider.getNextFromQueue();
if (task.id == TaskExecutor.TasksEnum.One) {
_taskExecutor.executeTaskOne();
return;
} else if (task.id == TaskExecutor.TasksEnum.Two) {
_taskExecutor.executeTaskTwo();
return;
} else if (task.id == TaskExecutor.TasksEnum.Three) {
_taskExecutor.executeTaskThree();
return;
}
//and so on...
如果需要,我可以将if-else
切换为switch
。
我相信存在一种更好的方法来实现类似的代码。
我想到的一件事是使用表(map)存储任务ID和指向相应函数的指针,但我不确定它是否有用并提供足够的性能。
另一件令我担忧的事情是通知机制。当TaskProvider
和TaskExecutor
是在不同线程上运行的两个独立实体时,会发生此问题。如果几个动作需要一些时间来完成执行,那就更糟了,我需要创建一个逻辑来让调用者等待结果。
例如,如果executeTaskTwo()
需要一些时间才能完成,我会在后台线程中执行它,这意味着executeTaskTwo()
几乎会立即返回,而任务本身仍然会执行。但是一旦结束,我如何通知呼叫者它的完成情况?
我猜这个解决方案涉及大量修改,也许是一些事件库(我之前从未使用过这些)。我需要一个起点。我猜有某种模式,但我不知道究竟是哪一种。
更新1:
有关一般架构和问题的更多信息 有三个实体:
Hardware
- 管理硬件信号(输入,输出)。只关心硬件,不问问为什么?Network
- 管理与设备的远程连接。只关心数据传输。同样,它并不关心数据代表什么。Controller
- 控制实际设备的任务/算法(此设备的功能)。这是设备的大脑。每个实体都在自己的线程上运行。有时,事件发生,一个实体需要将此事件发送给另一个实体(或所有实体)。例如,来自network
的命令打开一些由硬件管理的LED,或者,应该向network
(通知远程客户端)和controller
发出无法转动此LED的信号。 (执行紧急停止)。
现在每个实体(类)都有一组函数(方法),其他实体在这个实体执行某些操作时会调用这些函数。如果被调用的函数需要时间来执行,则调用者实体被阻塞,这是不好的。产生处理每个命令(或事件)的后台线程也感觉不对。
现在每个实体都拥有自己的命令队列并按顺序执行它的命令(execute(queue.getNext())
),但它无效,因为某些命令执行起来很快,而其他命令需要时间和资源。
答案 0 :(得分:1)
我相信有更好的方法来实现类似的代码。
switch语句就像你能得到的一样好。它(通常)会在您的机器代码中生成一个跳转表,该表将直接将程序计数器发送到该位置以继续执行。
使用map
(红黑树)存储ids
和pointers to functions
,效果不如switch
中的完美哈希效率高,可能会阻止内联优化
我会在后台线程中执行它,这意味着executeTaskTwo()几乎会立即返回。
我对多线程知之甚少,但你为什么要早点回来?
线程完成后,其余线程的线程是否为join
?
如果你的意思是主要线程继续做其他事情,那么你可以有一个std::atomic<bool>
来告诉你这个过程是否已经完成。如果只有一个线程写入它(工作线程),而其他线程读取(主线程),则行为定义良好。
如果您不想存储一堆布尔值并且只想知道某个流程是否仍在运行,那么您可以使用计数器,增量 在线程开始和结束时递减。
答案 1 :(得分:0)
你能把Task作为基类,让`getNextFromQueue()返回一个派生自它的具体类吗?这是一个简单的代码,可以给出想法/
class Task
{
public:
void execute() = 0;
}
class TaskOne : public Task
{
public:
void execute()
{
// execute the task here
}
}
所以你的代码看起来像是:
Task * task = _taskProvider.getNextFromQueue();
if (task)
task->execute()