假设我有一个类,每个对象应该独立地进行交互。例如,我可能在非现场许多服务器上的数据库中有各种表。但是,在内部,我碰巧知道某些表已链接,并且我可以通过将不需要任何响应的命令分组在一起来节省大量IO。我的目标是能够使用Table的接口编写代码:
void bar() {
// queue time is 500 milliseconds
Table::queue_time = 500;
Table a("foo"),b("baz"),c("cat");
// Call some function for members of this class
a.add(2);
b.add(5);
// Command is sent to database
sleep(1);
// This command will be sent later
c.add(5);
}
我希望这段代码实际上只发送两个命令到数据库。在第一次调用a.add()之后,我想要一种“队列”开始,在500ms之后将向数据库发出命令。当调用b.add()时,我希望将这条新指令放到这个队列中。但是,由于睡眠发生(并且时间足以让指令发送掉),我希望c.send()实际开始一个新的队列,它将在500ms内再次发送。
然而,诀窍在于,如果可能的话,我想在没有线程的情况下这样做。它是否可能(我倾向于不考虑)?如果没有,C ++中的哪些工具适合这项工作,如何在该线程处于休眠状态时从被编辑的对象进行通信?(实际上,这与数据库无关,所以不要担心这对他们来说无用)
答案 0 :(得分:3)
首先,我建议您阅读command pattern。您的命令应该是一个接一个地放在堆栈上的对象(如果您愿意,可以是列表),FIFO(先进先出)。但是你需要一个执行器来获取堆栈中的每个命令并执行它:你需要一个线程。我认为你需要准备好使用线程...你将无法完全避免它们。至于等待:一种特殊的命令。等待的命令(将当前线程置于休眠状态)。执行程序将一个接一个地执行每个命令,并且它将执行等待命令......好吧它会等待。就是这样!
只是不要在新线程中启动每个命令,因为你将破坏等待命令的目的。
撤消功能基于此模式。您将命令放在堆栈中并执行它们然后将它们放入“完成”堆栈中。如果你想回去,执行者“向后”执行“完成”堆栈的每个命令。我不会详细介绍实施细节,但如果您有兴趣,可以深入挖掘。
答案 1 :(得分:2)
“我想要一种”队列“开始”
“开始一个新的队列,将在500毫秒内再次发送”
队列的“开始”并不完全合情合理。队列通常是被动的东西。
“服务器”会从队列中挑选命令并执行它们。所以你想要一个通常获得命令并等待500毫秒的服务器。正确?
有时你想要覆盖500ms等待。正确?
所以你有一个“调度”问题。不是排队问题。您有以500毫秒调度间隔执行的命令,有时您希望改变该调度间隔。
请注意,时间表是“静态的”。你不需要在日程安排中间睡觉。你有一个CommandWithAWait
类执行命令并等待500毫秒。或者等待1秒钟。
a = CommandWithAWait( Table("foo").add(2), 500 );
b = CommandWithAWait( Table("bar").add(5), 1000 );
c = CommandWithAWait( Talbe("baz").add(5), 500 );
s= Schedule();
s.add( a );
s.add( b );
s.add( c );
s.go();
这样的东西似乎就是你所说的。在这种情况下,Schedule
类可以执行给定的命令,并以适当的延迟执行它们。没有真正的“线程”业务。
答案 2 :(得分:0)
如果你不能使用线程,那么你必须定期调用一个例程来测试经过的时间并根据需要刷新队列。
如果要使用线程,可以使用某种锁来保证访问队列的线程的互斥。必须为读取和写入获取锁定,并且在添加后不应修改队列中的元素。
另一种方法是简单地缓冲队列中的元素,当队列变得太大时,将显式刷新它。