互斥锁在忙碌时销毁 [英] mutex destroyed while busy

查看:648
本文介绍了互斥锁在忙碌时销毁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

EventHandler类有一个单例对象,用于接收来自主线程的事件.它将输入注册到向量,并创建一个运行lambda函数的线程,该函数会等待一段时间,然后再从向量中删除输入,以防止该输入的事件重复执行一段时间.

There is a singleton object of EventHandler class to receive events from the mainthread. It registers the input to a vector and creates a thread that runs a lambda function that waits for some time before deleting the input from the vector to prevent repeated execution of the event for this input for some time.

但是在忙于出错时,我的互斥体被破坏了.我不确定它发生在哪里以及如何发生.我什至不知道这意味着什么,因为它永远都不应被解构为单例对象.一些帮助,将不胜感激.

But I'm getting mutex destroyed while busy error. I'm not sure where it happened and how it happened. I am not even sure what it meant either because it shouldn't be de-constructed ever as a singleton object. Some help would be appreciated.

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();
    }
};

推荐答案

正在发生的事情是创建了线程

What is happening is that a thread is created

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

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

And then since removalCallBack is a local variable to the function RegisterBlock, when the function exits, the destructor for removalCallBack gets called which invokes std::terminate()

线程析构函数的文档

〜thread(); (自C ++ 11起)

~thread(); (since C++11)

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

Destroys the thread object. If *this still has an associated running thread (i.e. joinable() == true), std::terminate() is called.

但是根据时间的不同,线程退出时,线程仍然拥有 simpleLock (忙),根据规范,这会导致不确定的行为忙时毁坏错误.

but depending on timing, simpleLock is still owned by the thread (is busy) when the thread exits which according to the spec leads to undefined behavior, in your case the destroyed while busy error.

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

To avoid this error, you should either allow the thread to exist after the function exits (e.g. not make it a local variable) or block until the thread exits before the function exits using thread::join

在线程之后进行清理可能很棘手,尤其是当它们本质上用作占用相同地址空间的不同程序时,并且在这种情况下,很多次创建 manager 线程的方式都与您想象的一样其唯一的工作就是回收线程相关的资源.由于在 removalCallBack 创建的线程中完成的工作很简单,因此您的情况要容易一些,但是仍然需要清理.

Dealing with cleaning up after threads can be tricky especially if they are essentially used as different programs occupying the same address space, and in those cases many times a manager thread just like you thought of is created whose only job is to reclaim thread related resources. Your situation is a little easier because of the simplicity of the work done in the thread created by removalCallBack, but there still is cleanup to do.

如果线程对象将由new创建,那么尽管将清理C ++线程对象表示的系统线程使用的系统资源,但是该对象使用的内存将保持分配状态,直到调用delete为止.

If the thread object is going to be created by new, then although system resources used by the system thread the C++ thread object represents will get cleaned up, but the memory the object uses will remain allocated until delete is called.

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

Also, consider if the program exits while there are threads running, then the threads will be terminated, but if there is a mutex locked when that happens, once again there will be undefined behavior.

通常可以做的是保证线程不再运行是与它联接,但是尽管不会说,pthread_join手册页指出

What is usually done to guarantee that a thread is no longer running is to join with it, but though this doesn't say, the pthread_join man page states

一旦线程被分离,就无法与pthread_join(3)联接或使其再次可联接.

Once a thread has been detached, it can't be joined with pthread_join(3) or be made joinable again.

这篇关于互斥锁在忙碌时销毁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆