Qt QState机器同步问题:初始状态未在启动信号上设置

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

本文关键字:启动 信号 设置 初始状态 机器 QState 同步 问题 Qt      更新时间:2023-10-16

所以我试图理解Qt的QStateMachine的问题,我希望有人能帮助解释为什么会发生这种情况。我对QStateMachine的基本理解非常感兴趣,而不仅仅是修复。

首先考虑状态为 A、B 和事件 1 的状态机。事件 1 将您从 A 带到 B。A 是初始状态。

具体来说,这是为了维护邻居。在设备 X 中,我收到一条消息,邻居 Y 打招呼。这会导致邻居 X 为此新邻居 Y 错误地标记邻居状态机。这使得邻居状态机,然后调用 QStateMachine::start( ) ;

现在,在此状态机启动后,我需要继续处理此 hello 消息。所以起初我在做:

QStateMachine::start( ) ;
emit event 1 ;

我的理解是这是行不通的,因为 start 是一个异步调用,因此状态机在启动完成之前不会处于初始启动状态。这就引出了我的第一个问题。

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

认为这是问题所在,我通过将函数连接到状态机启动信号来稍微更改我的代码。然后,我更改了代码以在状态机未启动时对事件进行排队,并在调用启动信号后处理此挂起事件队列(并将它们发送到状态机)。

好吧,事实证明,当我开始信号时,初始状态仍未设置。 例如 QStateMachine::configuration( ).contains( initialstate ) == false。这就引出了我的第二个也是更大的问题。

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

这里的事件顺序是:

  1. 创建状态机
  2. 设置初始状态
  3. 启动状态机
  4. 接收事件 1
  5. 由于未启动队列事件 1
  6. 已启动信号
  7. 流程事件 1
  8. 由于是未知状态,因此什么都不做
  9. 接收事件 1
  10. 流程事件 1
  11. 现在处于状态 A. 过渡到状态 B。

顺序应为:

  1. 创建状态机
  2. 设置初始状态
  3. 启动状态机
  4. 接收事件 1
  5. 由于未启动队列事件 1
  6. 已启动信号
  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.什么都不做。

转换信号仅在状态更改(以 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