Skip to content

Commit

Permalink
More thread safety fixes
Browse files Browse the repository at this point in the history
Reorganize code so that the `ecm` and `updateInfo` variables are only
accessed from the Qt thread.

Signed-off-by: Addisu Z. Taddese <[email protected]>
  • Loading branch information
azeey committed Oct 13, 2021
1 parent de2e098 commit 5bd0107
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 17 deletions.
7 changes: 6 additions & 1 deletion include/ignition/gazebo/gui/GuiRunner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,15 @@ class IGNITION_GAZEBO_GUI_VISIBLE GuiRunner : public QObject
/// \param[in] _res Response containing new state.
private: void OnStateAsyncService(const msgs::SerializedStepMap &_res);

/// \brief Callback when a new state is received from the server.
/// \brief Callback when a new state is received from the server. Actual
/// updating of the ECM is delegated to OnStateQt
/// \param[in] _msg New state message.
private: void OnState(const msgs::SerializedStepMap &_msg);

/// \brief Called by the Qt thread to update the ECM with new state
/// \param[in] _msg New state message.
private: Q_INVOKABLE void OnStateQt(const msgs::SerializedStepMap &_msg);

/// \brief Update the plugins.
/// \todo(anyone) Move to GuiRunner::Implementation when porting to v5
private: Q_INVOKABLE void UpdatePlugins();
Expand Down
24 changes: 18 additions & 6 deletions src/gui/GuiRunner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@
using namespace ignition;
using namespace gazebo;

/// \todo(anyone) Move to GuiRunner::Implementation when porting to v5
/// \brief Mutex to protect the plugin update.
static std::mutex gUpdateMutex;
// Register SerializedStepMap to the Qt meta type system so we can pass objects
// of this type in QMetaObject::invokeMethod
Q_DECLARE_METATYPE(msgs::SerializedStepMap)

/////////////////////////////////////////////////
GuiRunner::GuiRunner(const std::string &_worldName)
{
qRegisterMetaType<msgs::SerializedStepMap>();

this->setProperty("worldName", QString::fromStdString(_worldName));

auto win = gui::App()->findChild<ignition::gui::MainWindow *>();
Expand Down Expand Up @@ -109,14 +111,24 @@ void GuiRunner::OnState(const msgs::SerializedStepMap &_msg)
{
IGN_PROFILE_THREAD_NAME("GuiRunner::OnState");
IGN_PROFILE("GuiRunner::Update");
// Since this function may be called from a transport thread, we push the
// OnStateQt function to the queue so that its called from the Qt thread. This
// ensures that only one thread has access to the ecm and updateInfo
// variables.
QMetaObject::invokeMethod(this, "OnStateQt", Qt::QueuedConnection,
Q_ARG(msgs::SerializedStepMap, _msg));
}

std::lock_guard<std::mutex> lock(gUpdateMutex);
/////////////////////////////////////////////////
void GuiRunner::OnStateQt(const msgs::SerializedStepMap &_msg)
{
IGN_PROFILE_THREAD_NAME("Qt thread");
IGN_PROFILE("GuiRunner::Update");
this->ecm.SetState(_msg.state());

// Update all plugins
this->updateInfo = convert<UpdateInfo>(_msg.stats());
QMetaObject::invokeMethod(this, "UpdatePlugins",
Qt::BlockingQueuedConnection);
this->UpdatePlugins();
this->ecm.ClearNewlyCreatedEntities();
this->ecm.ProcessRemoveEntityRequests();
}
Expand Down
11 changes: 1 addition & 10 deletions src/gui/plugins/component_inspector/ComponentInspector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ namespace ignition::gazebo

/// \brief Transport node for making command requests
public: transport::Node node;

/// \brief Mutex to protect componentsModel
public: QMutex mutex;
};
}

Expand Down Expand Up @@ -340,8 +337,6 @@ void ComponentInspector::Update(const UpdateInfo &,
if (this->dataPtr->paused)
return;

QMutexLocker locker(&this->dataPtr->mutex);

auto componentTypes = _ecm.ComponentTypes(this->dataPtr->entity);

// List all components
Expand Down Expand Up @@ -436,11 +431,7 @@ void ComponentInspector::Update(const UpdateInfo &,
// Add component to list
else
{
QMetaObject::invokeMethod(&this->dataPtr->componentsModel,
"AddComponentType",
Qt::DirectConnection,
Q_RETURN_ARG(QStandardItem *, item),
Q_ARG(ignition::gazebo::ComponentTypeId, typeId));
item = this->dataPtr->componentsModel.AddComponentType(typeId);
}

if (nullptr == item)
Expand Down

0 comments on commit 5bd0107

Please sign in to comment.