2016-03-15 63 views
1

想象我有以下幾點:使用操作當前對象的線程安全嗎?

struct A { 

    std::vector<int> _vect; 
    std::mutex _mutex; 

    void f() { 
     std::thread t1(&A::work, this); 
     std::thread t2(&A::work, this); 
     t1.join(); 
     t2.join(); 
    } 

    void work() { 
     std::vector<int> cvect; 
     while (true) { 
      bool keep = false; 
      _mutex.lock(); 
      // get_next() modify the internal state of this 
      keep = get_next(); 
      cvect = _vect; // copy of _vect 
      _mutex.unlock(); 
      if (!keep) break; 
      // Do some stuff that does not require the `this`, e.g.: 
      std::sort(cvect.begin(), cvect.end()); 
      int v = cvect.back() - cvect.front(); 
     } 
    } 

    bool get_next() { 
     // This methods modify _vect 
     _vect = std::vector<int>{1, 2, 3, 4}; // e.g. 
    } 
} 

int main() { 
    A a; 
    a.f(); 
    return 0; 
} 

以上編譯和工程(用更復雜的實現)。

  1. 它是否安全(如果不是,我怎樣才能使它安全?)?

  2. 期間_work可能發生什麼錯誤(這情況下沒有被正確處理?)?

+0

'執行線程't1'和't2'時'A'對象生活。那麼,爲什麼你認爲你的代碼不安全? – Tsyvarev

+0

@Tsyvarev我不認爲這是,但因爲我以前從來沒有操作'thread'和'mutex',我以爲我可能已經忘記了一些東西...... – Holt

+0

「不需要這個指針」意味着沒有成員變量是訪問? –

回答

4

目前的實現有一個微妙的錯誤。我想知道你是否也在真實代碼中擁有它。

while (true) { 
     _mutex.lock(); 
     // get_next() modify the internal state of this 
     if (!get_next()) break; 
     _mutex.unlock(); 

在這裏,break將退出循環並保持互斥鎖定。歡迎來到僵局!爲了解決這個微妙的問題,我真的建議避免使用mutex.lock()/unlock()。相反,應該使用std::lock_guardstd::unique_lock

+0

我沒有在我的真實代碼中(手動更新問題而不檢查...)。我不知道'lock_guard'和'unique_lock',我會檢查它們,謝謝你的回答! – Holt

0

的規則如下:

  1. 讀取和寫入到從不同的線程相同的變量是未定義的行爲。
  2. 閱讀和沒有任何鎖定或原子動作寫入同一變量同時可能導致存儲器不可見性。一個線程可能不是「讀」由其他線程
  3. 閱讀來自兩個不同的線程在同一變量寫的最新值是線程安全的。

您的問題:

//做一些東西,需要this指針。

如果「stuff」只是從this指向的成員中讀取的,那麼整個鎖定是多餘的。另一方面,如果一個線程更改this在某種比鎖定是強制性的。在這種情況下,鎖使並發動作線程安全

//做一些不需要this指針的東西。

再一次,如果在兩個線程中唯一採取的操作是讀取,則該方法是線程安全的。如果一個線程寫入變量(不論它是一個成員變量還是不行!線程只能看到內存地址),另一種是讀/寫它,比您必須鎖定變量或使用原子能它。

_work過程中可能發生什麼錯誤(這情況下是沒有正確處理 ?)?

未定義行爲的任​​何可能發生的土地。例如,當你解引用無效的內存地址時會發生什麼?

PS。使用標準的RAII包裝來鎖定互斥鎖,不要自己手動鎖定它。

相關問題