我QAbstractItemModel
的实施是听一些事件,并处理在一个单独的线程的更新。的更新处理可能会导致在示范布局和/或数据的变化。数据本身的存储是boost::mutex
- 保护的QAbstractItemModel
的接口函数每次调用(执行,如果我理解正确的话,在GUI线程),以及更新处理功能(在一个单独的线程)锁定互斥。它是好发出的信号layoutChanged / dataChanged同时锁定同一互斥的数据()/ rowCount时()/任何可能试图获得在同一时间?
一段代码:
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;
}
找到答案我自己的问题:如果模型属于不同的QThread,那么这种模式的信号将被连接使用Qt :: QueuedConnection查看,和它的罚款。但是,如果(默认)模式属于GUI的QThread(又名QCoreApplication ::实例() - >螺纹()),型号的插槽将被立即执行,从而导致数据)调用(,信息columnCount()等,从而,这是不行的。
QAbstractItemModel
是not thread safe.
这主要是因为跨线程信号得到排队。
试想一下,包含QList<int> list;
(忽略QModelIndex
)模型的以下情形:
background thread GUI thread + signal queue, abbreviations for readability
[MODEL] [VIEW] ( )
beginInsertRows(0, 1); ... ( rowsAboutToBeAdded(0, 1) = add(1) )
list << item(); (doing ( add(1) )
endInsertRows(); something ( add(1), rowsAdded(0, 1) = added(1) )
beginRemoveRows(0, 1); else) ( add(1), added(1), rowsAboutToBeRemoved(0, 1) = rem(1) )
list.removeAt(0); ... ( add(1), added(1), rem(1) )
endRemoveRows(0, 1); ... ( add(1), added(1), rem(1), rowsRemoved(0, 1) = rmvd(1) )
rowsAboutToBeAdded(0, 1); ( added(1), rem(1), rmvd(1) )
rowsAdded(0, 1); ( rem(1), rmvd(1) )
possible crash!
原因:
在rowsAdded(),视图迟早会呼叫
model()->data(model()->index(0, 0));
该模型索引是无效的,因为该模型没有行了。
在最好的情况下,它会返回一个无效的QVariant()
。
在最坏的情况下(无人防守的检查)模型试图访问list[0]
。