【问题标题】:Qt Locking and SignalsQt 锁定和信号
【发布时间】:2013-01-06 10:31:25
【问题描述】:

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

数据类:

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 类完全不受锁定的影响。

有什么想法吗?我有没有怀孕?

非常感谢 亚历克斯

【问题讨论】:

  • 你为什么使用 QReadWriteLock 而不是递归 QMutex?
  • 允许多个线程同时读取

标签: qt thread-safety locking


【解决方案1】:

您需要考虑模型中的对象代表什么。 Data 的哲学是可疑的。它拥有锁(拥有组合),但您不希望它是可自锁的。如果Data 是一个简单 数据包装器,那么它不应该拥有锁。所以要么让它处理自己的锁(然后你可以在发射之前解锁),或者把锁和发射Data移到AccessData

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多