首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用QReadWriteLock并发访问数据

用QReadWriteLock并发访问数据
EN

Code Review用户
提问于 2018-06-29 19:05:25
回答 1查看 229关注 0票数 2

使用Qt,我获得了这段代码,以保护线程之间对某些共享数据的访问。我很确定这个想法是正确的,但我不知道RVO和/或RAII是否有可能破坏get函数。我更习惯于C,虽然我理解这个概念,但我并不完全熟悉这两个概念的所有“难点”。

代码语言:javascript
运行
复制
class DataManager {
    Q_OBJECT

private:
    QVector<DataType> data;
    QReadWriteLock* rwLock;

public:
    DataManager() {
        rwLock = new QReadWriteLock();
    }
    ~DataManager() {
        delete rwLock;
    }
    Q_DISABLE_COPY(DataManager)

    QVector<DataType> getData() {
        QReadWriteLocker lock(rwLock);
        return data;
    }
    QVector<DataType>* beginModifyData() {
        rwLock->lockForWrite();
        return &data;
    }
    void endModifyData() {
        rwLock->unlock();
        emit dataChanged();
    }

signals:
    void dataChanged();
};

get函数中,在复制返回之前,RAII类型的类QReadWriteLocker是否有可能解锁?这样,一些等待写入的线程就可以覆盖正在返回的数据。

还有,如果有人写

代码语言:javascript
运行
复制
QVector<DataType>& myData = dataManager->getData();

由于RVO,他们是否有可能获得对实际数据的引用?

另外,我还想收到关于代码和idea本身的评论。下面我已经概述了我选择这种方法的原因。

  1. 简单易用。因为一个人只能读取数据的副本,所以他们不必担心同步和锁定。
  2. 利用Qt容器的隐式共享,在使用getData()时将永远不会生成实际的副本,从而使只读访问非常快。
  3. 因为在修改数据时,一个人获得了一个指向实际数据的指针,同样,在大多数情况下,除非某个线程正在缓存数据(或者其中一个副本尚未超出所得到的数据的范围),否则将不会创建副本。
  4. 从文档和代码来看,非递归QReadWriteLock在非竞争情况下是超快的,不会进行任何等待或上下文切换(对整数使用原子操作)。
  5. 如果需要的话,我可以在endModifyData函数中进行一些数据验证/修复。

谢谢。

EN

回答 1

Code Review用户

回答已采纳

发布于 2018-06-29 20:20:58

锁定

让我们看看这些成员函数实际上做了什么,以及哪些可能出错:

getData

getData中获得的锁基本上只确保没有人在内部修改data。一旦调用方获得返回的值,另一个线程就可以自由地修改它。

更清楚一点的是,RAII就是这样分解的:

代码语言:javascript
运行
复制
QVector<DataType> getData() {
    QReadWriteLocker lock(rwLock);
    QVector<DataType> temp = data;
    lock.~QReadWriteLocker(); // unlock
    return temp;
}

所以锁实际上不包括后续的使用。

beginModifyData/endModifyData

这两个成员函数将被串联调用。但是,如果beginModifyData的调用方忘记调用endModifyData (例如,因为抛出异常),会发生什么情况?显然,在这种情况下,锁永远不会被释放。

另外,有人可能会存储返回的指针,因此在释放锁后可以不同步地访问数据。

通用材料

为什么rwLock必须是指针,有什么具体的原因吗?它可能只是QReadWriteLock类型的代替。

beginModifyData为什么返回一个QVector<DataType>*而不是一个QVector<DataType>&有什么具体原因吗?

关于RVO

的问题

不,这不是返回值优化(RVO)的工作方式。为了更好地理解,如果编译器应用RVO,它可能会在概念上重写代码,如下所示:

代码语言:javascript
运行
复制
void getData(QVector<DataType>* return_value) {
    QReadWriteLocker lock(rwLock);
    // construct a new QVector<DataType> at the given address (to be passed from the callsite)
    new(return_value) QVector<DataType>(data);
}

// the callsite would be rewritten from
QVector<DataType> myData = dataManager->getData();
// to
QVector<DataType> myData; // uninitialized!
dataManger->getData(&myData);

因此,这显然不适用于引用。

如果没有RVO,引用将根本无法工作,因为返回对象的生存期在其声明结束时结束。但是,它将(至少部分)用于const QVector<DataType>&,因为这些临时人员的生命周期将得到延长(尽管它仍将引用副本)。

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

https://codereview.stackexchange.com/questions/197511

复制
相关文章

相似问题

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