使用Qt,我获得了这段代码,以保护线程之间对某些共享数据的访问。我很确定这个想法是正确的,但我不知道RVO和/或RAII是否有可能破坏get函数。我更习惯于C,虽然我理解这个概念,但我并不完全熟悉这两个概念的所有“难点”。
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是否有可能解锁?这样,一些等待写入的线程就可以覆盖正在返回的数据。
还有,如果有人写
QVector<DataType>& myData = dataManager->getData();由于RVO,他们是否有可能获得对实际数据的引用?
另外,我还想收到关于代码和idea本身的评论。下面我已经概述了我选择这种方法的原因。
getData()时将永远不会生成实际的副本,从而使只读访问非常快。endModifyData函数中进行一些数据验证/修复。谢谢。
发布于 2018-06-29 20:20:58
让我们看看这些成员函数实际上做了什么,以及哪些可能出错:
getData在getData中获得的锁基本上只确保没有人在内部修改data。一旦调用方获得返回的值,另一个线程就可以自由地修改它。
更清楚一点的是,RAII就是这样分解的:
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,它可能会在概念上重写代码,如下所示:
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>&,因为这些临时人员的生命周期将得到延长(尽管它仍将引用副本)。
https://codereview.stackexchange.com/questions/197511
复制相似问题