2017-03-01 180 views
0

我的QAbstractItemModel的实现正在侦听一些事件,并在单独的线程中处理更新。 处理更新可能会导致模型中的布局和/或数据更改。 数据本身的存储是boost::mutex - 受保护的,每次调用QAbstractItemModel的接口函数(如果我在GUI线程中理解正确,则执行)以及更新处理函数(在单独的线程中)锁定互斥锁。 可以在锁定data()/ rowCount()/可能同时尝试获取的同一个互斥锁时发出layoutChanged/dataChanged信号吗?QAbstractItemModel线程安全

一段代码:

class MyItemModel : public QAbstractItemModel { 
    Q_OBJECT 
public: 

    void processUpdate(const Update& update) { 
     Mservice.post([this, update]() { 
      boost::lock_guard<boost::mutex> lock (Mlock); 
      bool willModifyLayout = checkWillModifyLayout(update) 
      bool willModifyData = checkWillModifyData(update); 
      if (willModifyLayout) { 
       emit layoutAboutToBeChanged(); 
      } 
       Mdata.processUpdate(update); 
      if (willModifyLayout) { 
       emit layoutChanged(); 
      } 
      else if (willModifyData) { 
       emit dataChanged(); 
      }    
     }); 
    } 

    virtual QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE { 
     boost::lock_guard<boost::mutex> lock (Mlock); 
     if (index.isValid()) return Mdata.data(index, role); 
    } 

private: 
    boost::mutex Mmutex; 
    boost::asio::service Mservice; 
    boost::asio::thread MserviceThread; 
    DataStorage Mdata; 

} 
+0

我不认为在模型中首先存储被互斥保护的数据是一个好主意。这些视图经常会调用模型的'data()'方法,即使没有太多的并发性,锁定和解锁互斥量的开销可能就足够了。 – Dmitry

+0

如果你的数据足够大,你可以把它的管理封装在一些'QObject'中,它将通过信号将数据变化传达给实际的模型,这些模型将存储数据的轻量级“视图” - 例如,如果你的数据存储长文本,为了在视图中显示它们,模型可以包含每个项目的前140个字符。为了访问完整的数据(不适用于连接到模型的视图,以免经常发生访问),您可以创建自己的模型API,以便同步检索数据。 – Dmitry

+0

这确实是正确的方法。但使用boost的asio :: io_service来处理更新是由我使用的框架强制的。另一方面,如果QAbstractItemModel接口函数不抛出,即使是原始的代码也可能工作。如果processUpdate()在GUI线程处于data()调用时发出layoutChanged(),则等待锁定互斥锁 - 没有什么不好的事情会发生。 data()会返回一些错误的数据(或者可能是空的QVariant()),会显示它几分钟,然后它会处理信号,并且很快会开始显示正确的数据。 – thedimitrius

回答

0

找到答案我自己的问题: 如果模型属于不同的QThread,那么该模型的信号将被连接使用Qt :: QueuedConnection查看,这很好。 但是,如果(默认情况下)模型属于GUI QThread(又名QCoreApplication :: instance() - > thread()),则Model的槽将立即执行,导致调用data(),columnCount()等,因此,它不好。