0

我有一个从另一个类调用的简单数据类。

数据类:

class Data
{
public:
    QString getName() const
    {
        return this->mName;
    }

    void setName(AccessData* access, const QString& name)
    {
        this->mName = name;
        access->emitNameChanged(this);
    }
private:
    QString mName;
    QReadWriteLock mLock;
};

这是我用来获取/设置也处理锁定的新名称的类:

class AccessData : public QObject
{
public:
    QString getName(Data* data)
    {
        QReadLocker lock(&data->mLock);
        return data->getName();
    }

    void setName(Data* data, const QString& name)
    {
        QWriteLocker lock(&data->mLock);
        data->setName(this, name);
    }

    void emitNameChanged(Data* data)
    {
        emit this->nameChanged(data);
    }
signals:
    void nameChanged(AccessData* access, Data* data);
};

发生的情况是这样的:我使用 AccessData 类来读取和写入 Data 实例的名称。AccessData 类负责锁定读/写。但是,如您所见,Data 类在它的 setName() 方法中回调 AccessData 实例以正确发出有关更改的信号。注意:这只是伪代码,实际上它更复杂,这就是 Data 类需要能够通过它的调用者发出信号的原因。

这就是问题所在:

假设我有一个名为“d”的“Data”实例:Data* d; 我现在使用“AccessData”实例“a”来更改名称:a->setName(d, "new name"); 同时,我通过以下代码连接到 nameChanged() 信号:

...
void nameChanged(AccessData* access, Data* data)
{
    // Read the new name
    QString newName = access->getName();
}

这就是问题所在:

  1. 调用 a->setName(d, "new name")
  2. “d”现在被“a”锁定(写锁)
  3. "d" 发出关于名称更改的信号,但仍处于锁定状态
  4. 我连接到 nameChanged 信号的方法尝试访问 getName()
  5. 这将导致另一个 QReadLock 发出,这只会导致死锁

我该怎么做才能正确处理这个问题?我想到了两件事:

  1. 发出延迟的信号(也称为非阻塞)以使其进入循环。这不是我想要的,因为我希望立即推送信号。

  2. 在 Data 类中移动锁定/解锁内容并首先解锁,然后发出信号。这不是我想要的,因为我想让 Data 类完全不受锁定的影响。

任何的想法?我有没有怀孕?

非常感谢亚历克斯

4

1 回答 1

0

您需要考虑模型中的对象代表什么。的哲学Data是可疑的。它拥有锁(has-a composition),但您不希望它是可自锁的。如果Data打算成为一个简单的数据包装器,那么它不应该拥有锁。因此,要么让它处理自己的锁(然后你可以在发射之前解锁),要么将锁和发射移离DataAccessData.

如果出于某种原因您想保留呈现的设计,您可以通过初始化mLockQReadWriteLock::Recursive. 然后同一个线程可以多次锁定它 - 假设您仍然调用等量的unlock(). 但我个人的经验是,可重入锁定是失控/被误解的呼叫流的明确标志,并且是一种缓慢的误解,会狠狠地反击。虽然我确实阅读了一些理论上如果没有可重入锁就无法解决的概念,但我仍然必须看到一个实际上不可避免的概念。

于 2013-01-07T13:20:55.123 回答