堆栈上的竞争条件

时间:2018-04-27 11:23:26

标签: c++ multithreading mutex

我有简单的类Hello,我试图在不同的线程上调用成员函数say_hello。我创建了两个不同的实现hellos_in_stackhellos_in_heaphellos_in_heap按预期工作,但hellos_on_stack在成员变量_i上有竞争条件。如何使用mutex在堆栈中避免它?

#include <thread>
#include <iostream>
#include <vector>
#include <mutex>

std::mutex mu;

class Hello
{
  int _i;
public:
  Hello()
  {
      std::lock_guard<std::mutex> lock(mu);
      _i = 0;
  }
  ~Hello(){
  }
  void say_hello()
  {
      std::lock_guard<std::mutex> lock(mu);
      std::cout << "say_hello from thread " << ++_i << " " <<this << " " << std::this_thread::get_id() << std::endl;
  }
};

void hellos_in_stack()
{
    std::vector<std::thread> threads;
    for(int i = 0; i < 4; ++i)
    {
        Hello h;
        threads.push_back(std::thread(&Hello::say_hello, &h));
    }

    for(auto& thread : threads){
        thread.join();
    }
}


void hellos_in_heap()
{
    std::vector<std::thread> threads;
    std::vector<Hello *> hellos;
    Hello *h = nullptr;
    for(int i = 0; i < 4; ++i)
    {
        h = new Hello();
        hellos.push_back(h);
        threads.push_back(std::thread(&Hello::say_hello, h));
    }

    for(auto& thread : threads){
        thread.join();
    }

    for(auto hello : hellos){
        delete hello;
    }
}

int main()
{
    hellos_in_stack();
    hellos_in_heap();
    return 0;
}

1 个答案:

答案 0 :(得分:5)

让我们先描述一下竞争状况......

Hello h;正在主线程的堆栈上构建h。一旦for循环继续创建下一个线程,h将被销毁并创建另一个Hello - 可能(但不能保证)与前一个{相同的地址} {1}}。

h必须在运行其h方法的线程的生命周期内保持活动状态。

一种解决方案是在新线程的堆栈上创建say_hello。这可以这样做:

h

如果您仍然需要从主线程访问std::vector<std::thread> threads; for (int i = 0; i < 4; ++i) { threads.emplace_back([]() { Hello h; h.say_hello(); }); } 的实例,则另一个选项是将它们存储在容器中。

h

使用容器我们引入了一些更复杂的东西。现在,必须注意确保我们以安全的方式使用容器本身。在这种情况下,使用std::vector<std::thread> threads; std::list<Hello> hellos; for (int i = 0; i < 4; ++i) { hellos.emplace_back(); threads.emplace_back(&Hello::say_hello, &hellos.back()); } 代替std::list,因为在std::vector上调用emplace_back / push_back会导致其调整其缓冲区的大小。这会从正在运行的线程中销毁std::vector实例!

正在运行示例:https://ideone.com/F7STsf