c++ - 为什么程序会在 WSL 中挂起?

标签 c++ c linux signals windows-subsystem-for-linux

我的程序中有以下代码。

Thread* t = arg->thread;
//at this point, the new thread is being executed.
t->myId = TGetId();
void* (*functor)(void*) = t->functor;
void* fArg = arg->arg;
nfree(arg);
_INFO_PRINTF(1, "Launching thread with ID: %d", t->myId);
sigset_t mask;
sigfillset(&mask);         //fill mask with all signals
sigdelset(&mask, SIGUSR1); // allow SIGUSR1 to get to the thread.
sigdelset(&mask, SIGUSR2); // allow SIGUSR2 to get to the thread.
pthread_sigmask(SIG_SETMASK, &mask, NULL); //block some sigs

struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = TSignalHandler;
act.sa_mask = mask;
if(sigaction(SIGUSR1, &act, NULL))
{
    _ERROR_PRINT(1, "Could not set signal action.");
    return NULL;
}
if(sigaction(SIGUSR2, &act, NULL))
{
    _ERROR_PRINT(1, "Could not set signal action.");
    return NULL;
}
void* ret = functor(fArg);
t->hasReturned = true;
return ret;

执行此代码的线程将在 native linux 上正确调用信号处理程序。问题是,在适用于 Linux 的 Windows 子系统上,程序挂起并带有 SIGUSR1 或 SIGUSR2 是通过 pthread_kill 发送的,它向线程发送信号。为什么这适用于 native ubuntu(通过 VMWARE WORKSTATION 14)和 debian 和 fedora,但不适用于 WSL?

最佳答案

如果在调试器中运行时出现无法重现的挂起错误,则可以在重现挂起后将调试器附加到正在运行的进程。这不会让您在导致挂起时观察到变量的变化,但至少您可以获得挂起发生的确切位置的堆栈跟踪。

一旦知道挂起进程的进程 ID(假设它是 12345),您可以使用:

$ gdb -p 12345

或者,您可以使用会导致生成核心的信号终止进程。我喜欢使用 SIGTRAP,因为它很容易与 SIGSEGV 区分开来。

$ kill -SIGTRAP 12345

然后您可以使用 gdb 来发现进程卡在什么地方。

附加到正在运行的进程的好处是进程仍然存在。这允许您从调试器调用函数,这样可以更轻松地访问程序中内置的诊断信息。核心文件保留错误,如果挂起的错误难以重现,这将是有益的。

关于c++ - 为什么程序会在 WSL 中挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54791361/

相关文章:

linux - 使用终端在 ubuntu 上配置 postgresql

c++ - 将 `T const &&t` 与 `int const *` 匹配时 C++ 模板函数参数推导的说明

c++ - 将哈希值存储到 int

c++ - 在C++中捕获shell脚本退出状态

c 使用辅助函数填充二维数组

c - 缓冲区溢出的 C 代码问题

c - 从 EOL 中删除字符

c++ - 在一个项目中以 wchar_t 模式和普通模式使用 pugixml

c - -Wl,-wrap=symbol 不适用于共享库

c - 如何将字节数组转换为整数?