化QAbstractItemModel线程安全

问题描述 投票:0回答:2

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;

}
c++ multithreading qt model-view-controller model
2个回答
0
投票

找到答案我自己的问题:如果模型属于不同的QThread,那么这种模式的信号将被连接使用Qt :: QueuedConnection查看,和它的罚款。但是,如果(默认)模式属于GUI的QThread(又名QCoreApplication ::实例() - >螺纹()),型号的插槽将被立即执行,从而导致数据)调用(,信息columnCount()等,从而,这是不行的。


0
投票

QAbstractItemModelnot 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]

© www.soinside.com 2019 - 2024. All rights reserved.