Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
无用户代码的死锁 我在C++程序中使用了一个死锁,它使用了STD::线程,STD::互斥,STD::条件变量,等等。_C++_Multithreading_C++11_Visual Studio 2013_Deadlock - Fatal编程技术网

无用户代码的死锁 我在C++程序中使用了一个死锁,它使用了STD::线程,STD::互斥,STD::条件变量,等等。

无用户代码的死锁 我在C++程序中使用了一个死锁,它使用了STD::线程,STD::互斥,STD::条件变量,等等。,c++,multithreading,c++11,visual-studio-2013,deadlock,C++,Multithreading,C++11,Visual Studio 2013,Deadlock,这本身并没有什么奇怪的,直到我查看进程中每个线程的堆栈: 8532 0 Main Thread Main Thread msvcr120.dll!Concurrency::details::ExternalContextBase::Block Normal ntdll.dll!_ZwWaitForSingleObject@12() KernelBase.dll!_WaitForS

这本身并没有什么奇怪的,直到我查看进程中每个线程的堆栈:

8532    0   Main Thread Main Thread msvcr120.dll!Concurrency::details::ExternalContextBase::Block   Normal
                        ntdll.dll!_ZwWaitForSingleObject@12()    
                        KernelBase.dll!_WaitForSingleObjectEx@12()   
                        kernel32.dll!_WaitForSingleObjectExImplementation@12()   
                        msvcr120.dll!Concurrency::details::ExternalContextBase::Block() Line 145     
                        ntdll.dll!_ZwQueryVirtualMemory@24()     
                        kernel32.dll!_BasepFillUEFInfo@8()   
                        ntdll.dll!_ZwQueryInformationProcess@20()    
                        msvcr120.dll!_initterm(void (void) * * pfbegin, void (void) * * pfend) Line 954  
-

-

似乎没有线程在执行我的代码,我知道我们已经进入main,因为程序在挂起之前做了一些事情

我正在使用以下类与我的std::thread通信,以防我在那里犯了一些错误:

template <typename T>
class BlockingQueue
{
public:
    BlockingQueue() : _active(true) {}

    bool Get(T& out)
    {
        std::unique_lock<std::mutex> lock(_mutex);

        _cv.wait(lock, [&](){ return !_queue.empty() || !_active; });

        if (_queue.empty())
        {
            assert(!_active);

            return false;
        }

        out = std::move(_queue.front());
        _queue.pop();

        return true;
    }

    void Put(const T& in)
    {
        {
            std::unique_lock<std::mutex> lock(_mutex);

            _queue.push(in);
        }

        _cv.notify_one();
    }

    void Put(T&& in)
    {
        {
            std::unique_lock<std::mutex> lock(_mutex);

            _queue.push(std::move(in));
        }

        _cv.notify_one();
    }

    void Finish()
    {
        {
            std::unique_lock<std::mutex> lock(_mutex);

            _active = false;
        }

        _cv.notify_all();
    }

private:
    bool _active;
    std::mutex _mutex;
    std::condition_variable _cv;
    std::queue<T> _queue;
};
模板
类阻塞队列
{
公众:
BlockingQueue():_active(true){}
bool Get(T&out)
{
std::唯一的锁(互斥锁);
_cv.wait(lock,[&](){return!_queue.empty()| |!_active;});
if(_queue.empty())
{
断言(!\u活动);
返回false;
}
out=std::move(_queue.front());
_queue.pop();
返回true;
}
无效投入(常数T&in)
{
{
std::唯一的锁(互斥锁);
_排队。推(入);
}
_cv.通知_one();
}
无效投入(T&in)
{
{
std::唯一的锁(互斥锁);
_push(std::move(in));
}
_cv.通知_one();
}
空隙饰面()
{
{
std::唯一的锁(互斥锁);
_主动=假;
}
_cv.通知所有人();
}
私人:
布尔活跃;
std::mutex\u mutex;
std::条件变量cv;
std::queue\u queue;
};
我现在有两个想法:

  • 由于某种原因,Main已退出。这是一个PoC,所以当出现错误时,我们登录到stdout并调用exit()(是的,我知道,这不是最好的,这是从另一个用C++编写的C风格程序改编的)。我没有看到任何东西被记录到终端,但我想可能是输出被缓冲了,还没有被写出来
  • 调试器在某种程度上对我撒谎。通常在执行此操作时,它会将
    [下面的帧可能丢失/不正确]
    放入堆栈跟踪中,但如果不这样做,可能会发生这种情况

  • 事实证明,我未能替换队列中的项目,导致我的线程在从队列检索时死锁,这意味着调试器在欺骗我:(

    您应该在互斥锁内部通知,否则可能会遇到冲突:1.
    \u cv.wait()
    计算谓词;它返回
    false
    2.
    notify\u all
    称为3.
    \u cv.wait()中调用
    wait(lock)
    但不确定这是否是问题所在。我在看cppreference.com上std::condition_变量的文档,它似乎说在通知时不需要持有锁,事实上这样做是对性能的悲观(这是有意义的,因为任何因notify而唤醒的线程都会立即尝试获取锁并失败)“通知线程不需要将锁保持在与等待线程保持的锁相同的互斥体上;事实上,这样做是一种悲观的做法,因为通知线程会立即再次阻塞,等待通知线程释放锁。然而,一些实现(特别是pthreads的许多实现)认识到这种情况,并避免这种“匆忙等待”通过将等待线程从条件变量的队列直接传输到notify调用中的互斥体队列,而不唤醒它。“这就是他们所说的。在你的函数中放一些调试日志,看看它在哪里结束,这取决于情况。但是我检查了C++11的
    条件变量::wait
    ,它说在每次调用谓词之前都需要锁,所以它确实不能争用
    \u active
    6296    0   Worker Thread   msvcr120.dll!_threadstartex msvcr120.dll!Concurrency::details::ExternalContextBase::Block   Normal
                            ntdll.dll!_ZwWaitForSingleObject@12()    
                            KernelBase.dll!_WaitForSingleObjectEx@12()   
                            kernel32.dll!_WaitForSingleObjectExImplementation@12()   
                            msvcr120.dll!Concurrency::details::ExternalContextBase::Block() Line 145     
                            msvcp120.dll!std::_Thrd_startX(struct _Thrd_imp_t *,unsigned int (*)(void *),void *)     
                            msvcr120.dll!_callthreadstartex() Line 376   
                            msvcr120.dll!_threadstartex(void * ptd) Line 354     
                            kernel32.dll!@BaseThreadInitThunk@12()   
                            ntdll.dll!___RtlUserThreadStart@8()  
                            ntdll.dll!__RtlUserThreadStart@8()   
    
    template <typename T>
    class BlockingQueue
    {
    public:
        BlockingQueue() : _active(true) {}
    
        bool Get(T& out)
        {
            std::unique_lock<std::mutex> lock(_mutex);
    
            _cv.wait(lock, [&](){ return !_queue.empty() || !_active; });
    
            if (_queue.empty())
            {
                assert(!_active);
    
                return false;
            }
    
            out = std::move(_queue.front());
            _queue.pop();
    
            return true;
        }
    
        void Put(const T& in)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
    
                _queue.push(in);
            }
    
            _cv.notify_one();
        }
    
        void Put(T&& in)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
    
                _queue.push(std::move(in));
            }
    
            _cv.notify_one();
        }
    
        void Finish()
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
    
                _active = false;
            }
    
            _cv.notify_all();
        }
    
    private:
        bool _active;
        std::mutex _mutex;
        std::condition_variable _cv;
        std::queue<T> _queue;
    };