互斥在忙碌时被毁坏了

时间:2014-04-04 10:22:42

标签: multithreading c++11

有一个EventHandler类的单例对象来接收来自mainthread的事件。它将输入注册到向量并创建一个运行lambda函数的线程,该函数在从向量中删除输入之前等待一段时间,以防止在一段时间内重复执行该输入的事件。

但是我在忙碌的错误中被摧毁了互联网。我不确定它发生在哪里以及它是如何发生的。我甚至不确定它是什么意思,因为它不应该被解构为单身对象。一些帮助将不胜感激。

class EventHandler{
public:
    std::mutex simpleLock;
    std::vector<UInt32> stuff;
    void RegisterBlock(UInt32 input){
        stuff.push_back(input);
        std::thread removalCallBack([&](UInt32 input){
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            simpleLock.lock();
            auto it = Find(stuff, input);
            if (it != stuff.end())
                stuff.erase(it);
            simpleLock.simpleLock.unlock();
        }, input)
        removalCallBack.detach();
    }
    virtual EventResult ReceiveEvent(UInt32 input){
            simpleLock.lock();
            if (Find(stuff, input) != stuff.end()){
                RegisterBlock(input));
                //dostuff
            }
            simpleLock.simpleLock.unlock();
    }
};

1 个答案:

答案 0 :(得分:5)

正在发生的是创建一个线程

std::thread removalCallBack([&](UInt32 input){
   std::this_thread::sleep_for(std::chrono::milliseconds(200));
   simpleLock.lock();
   ...
removalCallBack.detach();

然后由于 removalCallBack 是函数 RegisterBlock 的局部变量,当函数退出时,调用 removalCallBack 的析构函数,调用 std :: terminate()

  

Documentation for thread destructor

     

〜螺纹(); (自C ++ 11起)

     

销毁线程对象。如果*仍然有一个关联的运行线程(即joinable()== true),则调用std :: terminate()。

但是根据时间安排,当线程退出时, simpleLock 仍然由线程拥有(忙),根据规范导致未定义的行为,在您的情况下在忙碌时被破坏错误。

要避免此错误,您应该在函数退出后允许线程存在(例如,不使其成为局部变量)或阻塞,直到线程退出,然后使用 thread :: join退出函数

在线程处理之后处理清理可能会非常棘手,特别是如果它们主要用作占用相同地址空间的不同程序,并且在这些情况下很多次会创建一个与您想到的 manager 线程一样其唯一的工作是收回与线程相关的资源。由于 removalCallBack 创建的线程中的工作非常简单,您的情况会更容易一些,但仍有待清理。

如果线程对象将由new创建,那么虽然C ++线程对象表示的系统线程使用的系统资源将被清除,但是对象使用的内存将保持分配,直到调用delete。

另外,考虑一下在线程运行时程序是否退出,然后线程将被终止,但如果在发生这种情况时锁定了互斥锁,则会再次出现未定义的行为。

通常用来保证线程不再运行的是加入它,但是this没有说,pthread_join手册页说明了

  

一旦线程被分离,它就不能与pthread_join(3)连接或再次成为可连接的。