2013-01-06 82 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()。但我個人的經驗是,可重入鎖定是失控/誤解呼叫流程的肯定標誌,以及一個將難以忍受的錯誤概念。雖然我的確瞭解了理論上的概念,如果沒有可重入的鎖定,這些理論概念是無法解決的,但我仍然必須看到一個實際上不可避免的問題。