【问题标题】:Mutex lock/unlock order互斥锁/解锁顺序
【发布时间】:2015-02-24 07:28:23
【问题描述】:

我很感兴趣互斥体(不取决于特定语言)必须保持锁定/解锁的顺序吗?
这是示例 C++ 代码:

std::mutex testVecMtx;
std::vector<int> testVec;

void testPush(int v){
  std::lock_guard<std::mutex> lk(testVecMtx);

  if (testVec.empty()){
    // wait some time to get more threads waiting on testVecMtx
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
  }

  testVec.push_back(v);
}

void Main_TEST(){
  std::list<std::thread> thList;

  for (int i = 0; i < 1000; i++){
    thList.push_front(std::thread(testPush, i));
  }

  for (auto &i : thList){
    if (i.joinable()){
        i.join();
    }
  }

  bool ok = true;

  for (int i = 0; i < (testVec.size() - 1) && ok; i++){
    ok = testVec[i + 1] - testVec[i] == 1;
  }

  if (ok){
    int stop = 243; // 1st breaking point here...
  }
  else{
    int stop = 432; // ...and 2nd here
  }
}

在 VS2013 中多次在调试和发布模式下运行此代码(进行一些更改以使代码未优化)模式后,我总是只在第一个断点处被击中。

【问题讨论】:

    标签: c++ mutex


    【解决方案1】:

    不,对订单没有任何保证。它只是碰巧在你的机器上以这种方式工作(例如,在我的电脑上ok 并不总是如此)。

    【讨论】:

    • 它在 Windows 下也不能以这种方式可靠地工作。来自MSDN:“不要假设先进先出 (FIFO) 顺序。内核模式 APC 等外部事件可以改变等待顺序。”在 OP 的测试中恰好没有这样的事件。
    • 此外,调试器的交互对事件的顺序有显着影响是很常见的(如果没有发生,则完全正常奇怪)。您可能会在调试器中获得一致的顺序,但在外部获得不同的顺序并且可能不太一致。
    • 您是否在您的计算机上运行此程序并遇到 ok 不正确的情况?
    • 无法保证,但不会经常发生。
    【解决方案2】:

    不,对订单没有任何保证。

    您可以尝试使用条件变量:

    #include <thread>
    #include <vector>
    #include <array>
    #include <list>
    #include <mutex>
    #include <condition_variable>
    
    const int MAX = 100; //***
    std::mutex testVecMtx;
    std::vector<int> testVec;
    std::array<std::condition_variable,MAX+1> Notifications; //***
    int Current = 0; //***
    
    void testPush(int v){
      std::unique_lock<std::mutex> lk(testVecMtx);
      while (v != Current){
        Notifications[v].wait(lk);
      }
    
      testVec.push_back(v);
      Current++;
    
      if (v != MAX)
        Notifications[v+1].notify_all();
    }
    
    int main(){
      std::list<std::thread> thList;
    
      for (int i = 0; i < MAX; i++){
        thList.push_front(std::thread(testPush,i));
      }
    
      for (auto &i : thList){
            i.join();
      }
    
      bool ok = true;
    
      for (int i = 0; i < (testVec.size() - 1) && ok ;i++){
        ok = (testVec[i + 1] - testVec[i]) == 1;
    
      }
    
      if (ok){
        int stop = 243; // 1st breaking point here...
    //    std::cout<<"Ok"<<std::endl;
      }
      else{
        int stop = 432; // ...and 2nd here
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-05-23
      • 1970-01-01
      • 2021-02-03
      • 2022-07-31
      • 2010-11-22
      • 2021-12-23
      • 2012-12-25
      • 1970-01-01
      相关资源
      最近更新 更多