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;
}
我不認爲在模型中首先存儲被互斥保護的數據是一個好主意。這些視圖經常會調用模型的'data()'方法,即使沒有太多的併發性,鎖定和解鎖互斥量的開銷可能就足夠了。 – Dmitry
如果你的數據足夠大,你可以把它的管理封裝在一些'QObject'中,它將通過信號將數據變化傳達給實際的模型,這些模型將存儲數據的輕量級「視圖」 - 例如,如果你的數據存儲長文本,爲了在視圖中顯示它們,模型可以包含每個項目的前140個字符。爲了訪問完整的數據(不適用於連接到模型的視圖,以免經常發生訪問),您可以創建自己的模型API,以便同步檢索數據。 – Dmitry
這確實是正確的方法。但使用boost的asio :: io_service來處理更新是由我使用的框架強制的。另一方面,如果QAbstractItemModel接口函數不拋出,即使是原始的代碼也可能工作。如果processUpdate()在GUI線程處於data()調用時發出layoutChanged(),則等待鎖定互斥鎖 - 沒有什麼不好的事情會發生。 data()會返回一些錯誤的數據(或者可能是空的QVariant()),會顯示它幾分鐘,然後它會處理信號,並且很快會開始顯示正確的數據。 – thedimitrius