【问题标题】:Qt QStateMachine Sync Problems: Initial State not set on Started SignalQt QStateMachine 同步问题:初始状态未在启动信号上设置
【发布时间】:2012-04-08 01:29:01
【问题描述】:

所以我试图了解 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) 为什么发出started信号时我不在初始状态。

这里的事件顺序是:

  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。什么都不做。

【问题讨论】:

    标签: c++ qt state-machine qstatemachine


    【解决方案1】:

    只有在状态改变后(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

    【讨论】:

    • 谢谢,这就像一个魅力。我仍然不明白为什么当调用 start 信号时我们不处于初始状态,但我想此时这并不重要。非常感谢。
    • 我不推荐使用 qApp->processEvents() 的模式。这样做的原因是,您不仅要处理您感兴趣的事件,还要处理队列中的任何事件,因此您将不得不处理其他情况。 IMO 这种嵌套从来都不是一个好主意。
    猜你喜欢
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多