2013-01-06 83 views
0

我有一个简单的数据类,从另一个类中调用。Qt锁定和信号

数据类:

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类读取和写入数据实例的名称。 AccessData类负责锁定读/写。但是,您可以看到Data类在它的setName()方法中调用了AccessData实例,以正确发出有关更改的信号。注意:这只是伪代码,实际上它更复杂,因此Data类需要能够通过它的调用者发出信号。

而这里的问题:

说我有“数据”被称为“d”的一个实例:数据* d; 我现在使用“AccessData”实例“a”来更改名称:a-> setName(d,“new name”); 与此同时,我conncected到nameChanged()信号与此代码:

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

而这里的问题:

  1. 调用A->的setName(d, “新名字”)
  2. “d”现在是由“A”(写锁定)锁定
  3. “d”发出有关名称变化虽然仍锁定
  4. 我连接到nameChanged信号方法试图访问的getName信号()
  5. 这将导致再次发布QReadLock它只是导致死锁

我能做些什么来妥善处理这个?有这么走过来对我两件事情:

  1. 散发出延迟(又名非阻塞)的信号,让它进入循环。 这不是我想要的,因为我想要立即推送信号。

  2. 移动Data类中的锁定/解锁物件并首先解锁,然后发出信号。 这不是我想要的,因为我想让Data类完全免于锁定。

任何想法?我有一个怀念概念吗?

非常感谢 亚历

+0

为什么你使用QReadWriteLock而不是递归QMutex? – Mat

+0

允许多个线程同时读取 – anderswelt

回答

0

你需要让你的头脑什么模型中的对象表示。 Data的哲学是可疑的。它拥有锁(has-a组成),但你不希望它是自锁的。如果Data意图是简单数据包装,那么它不应该拥有该锁。因此,要么允许它处理自己的锁(然后您可以在发射前解锁),或者将锁和发射太Data移动到AccessData

如果由于某种原因您想要保留所提供的设计,您可以通过初始化mLock作为QReadWriteLock::Recursive来“解决”这个问题。然后,同一个线程可以多次锁定它 - 因为您仍然呼叫等效金额为unlock()。但我个人的经验是,可重入锁定是失控/误解呼叫流程的肯定标志,以及一个将难以忍受的错误概念。虽然我的确了解了理论上的概念,如果没有可重入的锁定,这些理论概念是无法解决的,但我仍然必须看到一个实际上不可避免的问题。