2017-03-01 181 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()等,因此,它不好。