简体   繁体   English

Qt QStateMachine 同步问题:未在启动信号上设置初始 State

[英]Qt QStateMachine Sync Problems: Initial State not set on Started Signal

So I am trying to understand a problem with Qt's QStateMachine and I'm hoping someone can help explain why this is happening.所以我试图了解 Qt 的 QStateMachine 的问题,我希望有人能帮助解释为什么会这样。 I'm very interested in the fundamental understanding of QStateMachine rather than just the fix.我对 QStateMachine 的基本理解非常感兴趣,而不仅仅是修复。

First consider the state machine with states A, and B and event 1. Event 1 brings you from A to B. A is the initial state.首先考虑状态为 A、B 和事件 1 的 state 机器。事件 1 将您从 A 带到 B。A 是初始的 state。

Specifically this is for maintaining neighbors.具体来说,这是为了维护邻居。 In device XI get a message where a neighbor Y says hello.在设备 XI 中收到邻居 Y 打招呼的消息。 This causes neighbor X to malloc a neighbor state machine for this new neighbor Y. This makes the neighbor state machine and then calls QStateMachine::start( );这导致邻居 X 到 malloc 一个邻居 state 机器为这个新邻居 Y。这使得邻居 state 机器然后调用 QStateMachine::start();

Now after this state machine is started I need to continue processing this hello message.现在,在这台 state 机器启动后,我需要继续处理这条问候消息。 So at first I was doing:所以起初我在做:

QStateMachine::start( ) ;
emit event 1 ;

My understanding is this won't work because start is an async call and so the state machine is not in its initial start until after start is done.我的理解是这是行不通的,因为 start 是一个异步调用,因此 state 机器在启动完成后才处于初始启动状态。 That leads me to my first question.这引出了我的第一个问题。

1) So the state machine start gets placed in the qapp event queue but isn't emit an async call as well? 1) 所以 state 机器启动被放置在 qapp 事件队列中,但也没有发出异步调用? Won't the event 1 be placed in the event queue after the start and so wouldn't that mean we will be in the initial state?事件 1 不会在开始后放入事件队列中,所以这是否意味着我们将在初始 state 中? Or is the emit not an async call?或者 emit 不是异步调用?

Thinking this was the problem I changed my code a little by connecting a function to the state machine started signal.认为这是问题所在,我通过将 function 连接到 state 机器启动信号来稍微更改我的代码。 I then changed my code to queue up the events if the state machine is not started and I process this queue of pending events (and emit them to the state machine) after the started signal is called.然后,如果 state 机器未启动,我更改代码以对事件进行排队,并在调用启动信号后处理此待处理事件队列(并将它们发送到 state 机器)。

Well it turns out the initial state is STILL not set when I get started signal.好吧,当我开始信号时,最初的 state 仍然没有设置。 eg QStateMachine::configuration( ).contains( initialstate ) == false.例如 QStateMachine::configuration().contains(initialstate) == false。 This leads me to my second and bigger question.这引出了我的第二个也是更大的问题。

2) Why when the started signal is emitted am I not in the initial state. 2)为什么发出启动信号时我不在初始state中。

The sequence of events here is:这里的事件顺序是:

  1. Create state machine创建 state 机器
  2. Set initial state设置初始 state
  3. Start state machine启动state机器
  4. Receive event 1接收事件 1
  5. Since not started queue event 1由于未启动队列事件 1
  6. Started signal rxed开始信号 rxed
  7. Process event 1处理事件 1
  8. Since is unknown state do nothing由于未知 state 什么都不做
  9. Receive event 1接收事件 1
  10. Process event 1处理事件 1
  11. Now in state A. transition to state B.现在在 state A. 过渡到 state B.

The sequence should be:顺序应该是:

  1. Create state machine创建 state 机器
  2. Set initial state设置初始 state
  3. Start state machine启动state机器
  4. Receive event 1接收事件 1
  5. Since not started queue event 1由于未启动队列事件 1
  6. Started signal rxed开始信号 rxed
  7. Process event 1处理事件 1
  8. Now is state A. transition to state B.现在是 state A. 过渡到 state B.
  9. Receive event 1接收事件 1
  10. Process event 1处理事件 1
  11. Now is state B. Do nothing.现在是 state B.什么都不做。

Or event better I wish I didn't have to queue the event.或者更好的活动我希望我不必排队参加活动。 I wish I could do this:我希望我能这样做:

  1. Create state machine创建 state 机器
  2. Set initial state设置初始 state
  3. Start state machine启动state机器
  4. Receive event 1接收事件 1
  5. Process event 1处理事件 1
  6. Now is state A. transition to state B.现在是 state A. 过渡到 state B.
  7. Receive event 1接收事件 1
  8. Process event 1处理事件 1
  9. Now is state B. Do nothing.现在是 state B.什么都不做。

Transition signals are only connected after the state changes (in QStateMachinePrivate::registerSignalTransition ) and the connection is not a queued connection:转换信号仅在 state 更改后连接(在QStateMachinePrivate::registerSignalTransition中)并且连接不是排队连接:

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

For the "event 1" to be received, the machine must already be in a state that react to that signal.对于要接收的“事件 1”,机器必须已经处于对该信号做出反应的 state 中。 Even it was a queued connection, the slot would be queued but only after the signal was received, which it isn't since there is no connection yet at that point.即使它是排队连接,插槽也会排队,但只有在收到信号后才会排队,因为此时还没有连接。

To solve your problem, you can wait for the machine is in "state A" before emitting the signal:要解决您的问题,您可以在发出信号之前等待机器处于“状态 A”:

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

Or you can delay the signal emission and queue it after the other already queued operations:或者你可以延迟信号发射并在其他已经排队的操作之后排队:

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

The started signal is emitted before the initial state is set (according to source code), which can be helpful if you have initialization to do before any state is set. started信号在设置初始 state 之前发出(根据源代码),如果您在设置任何 state 之前要进行初始化,这会很有帮助。 If you need to wait for the initial state, you can use the signal QState::entered .如果需要等待初始的 state,可以使用信号QState::entered

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM