2016-03-15 34 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包装来锁定互斥锁,不要自己手动锁定它。

相关问题