2012-04-08 54 views
1

所以我想了解Qt的QStateMachine问题,我希望有人可以帮助解释为什么会发生这种情况。我对QStateMachine的基本理解非常感兴趣,而不仅仅是修复。Qt QStateMachine同步问题:初始状态未设置开始信号

首先考虑具有状态A,B和事件1的状态机。事件1将您从A带到B.A是初始状态。

具体来说,这是为了维护邻居。在设备X中,我收到一条消息,说明邻居Y说你好。这导致邻居X为这个新的邻居Y分配一个邻居状态机。这使邻居状态机,然后调用QStateMachine :: start();

现在这个状态机启动后,我需要继续处理这个hello消息。所以刚开始我是做:

我的理解是这是行不通的,因为开始是一个异步调用,因此状态机不在其最初的启动开始之前完成之后。这导致我第一个问题。

1)所以状态机启动被放置在qapp事件队列中,但不会发出异步调用?事件1不会在开始后被置于事件队列中,那么这是否意味着我们将处于初始状态?或者是不是异步调用?

认为这是问题我通过将一个函数连接到状态机启动信号来改变我的代码。然后,如果状态机未启动,则更改我的代码以排队事件,并在调用启动的信号后处理未决事件队列(并将它们发送给状态机)。

事实证明,初始状态仍然没有设置,当我开始信号。例如QStateMachine :: configuration().contains(initialstate)== false。这导致我第二个也是更大的问题。

2)为什么当启动的信号发射时我不在初始状态。

此事件的顺序是:

  1. 创建状态机
  2. 设置初始状态
  3. 启动状态机
  4. 接收事件1
  5. 由于没有启动队列事件1
  6. 启动信号rxed
  7. 处理事件1
  8. 既然是未知的状态束手无策
  9. 接收事件1
  10. 处理事件1
  11. 现在处于状态A转移到状态B.

的顺序应该是:

  1. 创建状态机
  2. 设置初始状态
  3. 启动状态机
  4. 接收事件1
  5. 由于没有启动队列事件1
  6. 开始信号rxed
  7. 个处理事件1
  8. 现在是状态A转移到状态B.
  9. 接收事件1
  10. 处理事件1
  11. 现在是状态B.什么也不做。

或事件更好我希望我不必排队事件。我希望我能做到这一点:

  1. 创建状态机
  2. 设置初始状态
  3. 启动状态机
  4. 接收事件1
  5. 处理事件1
  6. 现在是状态A.过渡到状态B.
  7. 接收事件1
  8. 过程事件1
  9. 现在是国家B.什么都不做。

回答

6

过渡的信号的状态改变(在QStateMachinePrivate::registerSignalTransition)后仅连接和连接不是排队连接:

bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator, 
            signalEventGenerator->metaObject()->methodOffset()); 

对于“事件1”被接收,所述机器必须已经处于对该信号作出反应的状态。即使是排队的连接,插槽也会排队,但只有在收到信号后才能排队,但这并不是因为此时没有连接。

解决你的问题,你可以等待机器处于“状态A”发射信号之前:

machine->start(); 
qApp->processEvents(); 
emit event1(); 

或者你可以延迟信号的发射和其他已排队的操作后,排队吧:之前被设定的初始状态(如源代码),它可以是有益的,如果你有初始化设置任何状态之前做

machine->start(); 
QTimer::singleShot(0, emitter, SIGNAL(event1())); 
// or 
QMetaObject::invokeMethod(emitter, "event1", Qt::QueuedConnection); 

started信号被发射。如果您需要等待初始状态,则可以使用信号QState::entered

+0

谢谢,这就像一个魅力。我仍然不明白为什么当开始的信号被调用时,我们并不处于初始状态,但我想这一点并不重要。非常感激。 – 2012-04-08 02:30:06

+0

我不会推荐使用qApp-> processEvents()的模式。原因是你不仅要处理你感兴趣的事件,还要处理队列中的任何事情,所以你将不得不处理更多的事件。这种嵌套从来不是一个好主意IMO。 – mhstnsc 2013-11-12 11:32:37