首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QAbstractItemModel线程安全

QAbstractItemModel线程安全
EN

Stack Overflow用户
提问于 2017-03-01 20:59:28
回答 2查看 2.1K关注 0票数 4

我的QAbstractItemModel实现是侦听一些事件,并在一个单独的线程中处理更新。更新的处理可能导致模型中的布局和/或数据更改。数据本身的存储是受boost::mutex保护的,每次调用QAbstractItemModel的接口函数(如果我正确理解的话,在GUI线程中执行),以及更新处理函数(在单独的线程中)锁定互斥对象。在锁定数据()/rowCount()/whatever可能试图同时获取的同一个互斥对象的同时发出布局变更/dataChanged信号可以吗?

一段代码:

代码语言:javascript
复制
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;

}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-10 08:22:08

找到了对我自己的问题的答案:如果模型属于不同的QThread,那么这个模型的信号将被连接到使用Qt::QueuedConnection的视图,这很好。但是,如果(默认情况下)模型属于GUI QThread (a.k.a )。QCoreApplication::instance()->thread(),将立即执行模型的插槽,从而导致对data()、columnCount()等的调用,因此,这是不正常的。

票数 2
EN

Stack Overflow用户

发布于 2019-02-04 15:52:55

QAbstractItemModel thread safe.

这主要是因为跨线程的信号被排队。

想象一下包含QList<int> list;的模型的以下场景(忽略QModelIndex):

代码语言:javascript
复制
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()中,视图迟早会调用

代码语言:javascript
复制
model()->data(model()->index(0, 0));

此模型索引无效,因为模型不再有行。

在最好的情况下,它只返回一个无效的QVariant()

在最坏的情况下(没有防御性检查),模型试图访问list[0]

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42541948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档