我的QAbstractItemModel实现是侦听一些事件,并在一个单独的线程中处理更新。更新的处理可能导致模型中的布局和/或数据更改。数据本身的存储是受boost::mutex保护的,每次调用QAbstractItemModel的接口函数(如果我正确理解的话,在GUI线程中执行),以及更新处理函数(在单独的线程中)锁定互斥对象。在锁定数据()/rowCount()/whatever可能试图同时获取的同一个互斥对象的同时发出布局变更/dataChanged信号可以吗?
一段代码:
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;
}发布于 2017-10-10 08:22:08
找到了对我自己的问题的答案:如果模型属于不同的QThread,那么这个模型的信号将被连接到使用Qt::QueuedConnection的视图,这很好。但是,如果(默认情况下)模型属于GUI QThread (a.k.a )。QCoreApplication::instance()->thread(),将立即执行模型的插槽,从而导致对data()、columnCount()等的调用,因此,这是不正常的。
发布于 2019-02-04 15:52:55
QAbstractItemModel是 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]。
https://stackoverflow.com/questions/42541948
复制相似问题