【问题标题】:Program hangs in Visual Studio debugger程序在 Visual Studio 调试器中挂起
【发布时间】:2015-05-12 15:41:20
【问题描述】:

一些背景知识:我正在尝试跟踪一个让我非常头疼的错误。经过许多死胡同(见this question),我终于得到了这段代码:

#include <thread>
#include <vector>
#include <iosfwd>
#include <sstream>
#include <string>
#include <windows.h>

int main()
{
    SRWLOCK srwl;
    InitializeSRWLock(&srwl);
    for(size_t i=0;i<1000;++i)
    {
        std::vector<std::thread>threads;
        for(size_t j=0;j<100;++j)
        {
            OutputDebugString(".");
            threads.emplace_back([&](){
                AcquireSRWLockExclusive(&srwl);
                //Code below modifies the probability to see the bug.
                std::this_thread::sleep_for(std::chrono::microseconds(1));
                std::wstringstream wss;
                wss<<std::this_thread::get_id();
                wss.str();
                //Code above modifies the probability to see the bug.
                ReleaseSRWLockExclusive(&srwl);});
        }
        for(auto&t:threads){t.join();}
        OutputDebugString((std::to_string(i)+"\n").data());
    }
    return 0;
}

当我在 VS 2013 调试器中运行此代码时,程序会挂起并显示如下输出:

....................................................................................................0
....................................................................................................1
....................................................................................................2
...........................

奇怪的是,如果我暂停调试器并检查正在发生的事情,其中​​一个线程在 AcquireSRWLockExclusive 中(在 NtWaitForAlertByThreadId 中),显然程序没有理由挂起。当我点击恢复时,程序会愉快地继续打印一些内容,直到再次被阻止。

你有什么想法吗?

更多信息:

  • 据我所知,此错误仅存在于 Windows 8.1 上。
  • 我试过 VS2013.4 和 VS2015 RC。
  • 我可以在两台不同的 Windows 8.1 计算机上重现它。
  • 其中一台机器被格式化,RAM、CPU 和磁盘测试(我认为是故障,因为起初我只能观察到这台特定机器上的错误)
  • 我永远无法在 Windows 7 上重现它。
  • 修改 cmets 之间的代码以观察错误可能很有用。当我添加微秒睡眠时,我终于可以在另一台计算机上重现该错误。
  • 使用 VS2015 RC,我可以使用简单的 std::mutex 重现相同的行为。然而,在 VS2013 上,SRWLOCK 似乎是强制观察错误的。

【问题讨论】:

  • 可能是您处于死锁状态,一旦您进入调试器,它会更改同步并且死锁消失。
  • @NathanOliver 这怎么可能?代码中只有一个互斥锁。
  • 程序在调试器外运行时是否挂起?
  • @RetiredNinja 它不会挂在调试器之外。
  • 看着很痛苦。 std::thread 建立在并发时间之上。一分钱一磅,请改用&lt;ppl.h&gt; 中的Concurrency::reader_writer_lock。这可能会破坏交易,请考虑就此致电 Microsoft 支持。

标签: c++ visual-studio c++11 visual-c++


【解决方案1】:

此问题是由 Windows 8.1 的 2014 年春季更新中引入的操作系统调度程序错误引起的。此问题的修补程序已于 2015 年 5 月发布,可通过 https://support.microsoft.com/en-us/kb/3036169 获取。

【讨论】:

  • 我尝试了修复程序,它解决了问题。不过,它似乎要慢得多。
【解决方案2】:

对我来说,这看起来像是 Windows 操作系统中的一个错误,我有不同的代码变体,在 2014 年 4 月更新后,在 Win 8.1 / Server 2012R2 的调试器下使用新的 Vista 原语挂起。还有一些线程池等待功能也挂起。看起来它主要与等待/锁定时其他线程完成执行有关。这是在 NtWaitForAlertByThreadId() 中总是挂在调试器下的简单代码:

#include <windows.h>

#include <stdio.h>
#include <conio.h>
#include <tchar.h>

#pragma optimize("",off)
VOID CALLBACK _WorkCallback(PTP_CALLBACK_INSTANCE Instance, PVOID pUser, PTP_WORK Work)
{
    for (int i = 0; i < INT_MAX / 256; i++) {}
}

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    for (int i = 0; i < INT_MAX / 256; i++) {}
    return 0;
}
#pragma optimize("",on)

int _tmain(int argc, _TCHAR* argv[])
{
    LONGLONG c = 0;

    while(!_kbhit())
    {
        PTP_WORK ptpw = CreateThreadpoolWork(&_WorkCallback, NULL, NULL);
        if (ptpw != NULL) 
        {
            for(long i = 0; i < 3; i++) SubmitThreadpoolWork(ptpw);

            CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

            WaitForThreadpoolWorkCallbacks(ptpw, FALSE);
            CloseThreadpoolWork(ptpw);
        }

        printf("%I64d                                 \r", c++);
    }

    _getch();
    return 0;
}

很遗憾,我不知道在哪里向 Microsoft 报告。

【讨论】:

  • 我也可以在我的系统上重现挂起。
猜你喜欢
  • 1970-01-01
  • 2023-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-27
  • 1970-01-01
  • 2016-02-21
  • 1970-01-01
相关资源
最近更新 更多