简体   繁体   English

QueueUserAPC - 抛出异常崩溃,可能是 mingw 错误

[英]QueueUserAPC - throwing exception crashes, possible mingw bug

Solved: I upgraded from mingw 4.6.2 to 4.7.0 and it works perfectly, guess it was just a bug解决:我从 mingw 4.6.2 升级到 4.7.0 并且运行良好,我猜这只是一个错误

I started to do some research on how terminate a multithreaded application properly and I found those 2 post( first , second ) about how to use QueueUserAPC to signal other threads to terminate.我开始研究如何正确终止多线程应用程序,我发现了关于如何使用QueueUserAPC向其他线程发出终止信号的 2 篇文章(第一篇, 第二篇)。

I thought I should give it a try, and the application keeps crashing when I throw the exception from the APCProc.我想我应该试一试,当我从 APCProc 抛出异常时,应用程序一直崩溃。

Code:代码:

#include <stdio.h>
#include <windows.h>

class ExitException
{
public:
    char *desc;
    DWORD exit_code;

    ExitException(char *desc,int exit_code): desc(desc), exit_code(exit_code)
    {}
};

//I use this class to check if objects are deconstructed upon termination
class Test 
{
public:
    char *s;

    Test(char *s): s(s)
    {
        printf("%s ctor\n",s);
    }

    ~Test()
    {
        printf("%s dctor\n",s);
    }
};

DWORD CALLBACK ThreadProc(void *useless)
{
    try
    {
        Test t("thread_test");

        SleepEx(INFINITE,true);

        return 0;
    }
    catch (ExitException &e)
    {
        printf("Thread exits\n%s %lu",e.desc,e.exit_code);
        return e.exit_code;
    }
}

void CALLBACK exit_apc_proc(ULONG_PTR param)
{
    puts("In APCProc");
    ExitException e("Application exit signal!",1);
    throw e;

    return;
}

int main()
{
    HANDLE thread=CreateThread(NULL,0,ThreadProc,NULL,0,NULL);

    Sleep(1000);

    QueueUserAPC(exit_apc_proc,thread,0);

    WaitForSingleObject(thread,INFINITE);

    puts("main: bye");

    return 0;
}

My question is why does this happen?我的问题是为什么会这样?

I use mingw for compilation and my OS is 64bit.我使用 mingw 进行编译,我的操作系统是 64 位。

Can this be the reason?I read that you shouldn't call QueueApcProc from a 32bit app for a thread which runs in a 64bit process or vice versa, but this shouldn't be the case.这可能是原因吗?我读到你不应该从 32 位应用程序为在 64 位进程中运行的线程调用QueueApcProc ,反之亦然,但事实并非如此。

EDIT: I compiled this with visual studio's c++ compiler 2010 and it worked flawlessly, it is possible that this is a bug in gcc/mingw?编辑:我用 visual studio 的 c++ 编译器 2010 编译了它,它工作得很好,这可能是 gcc/mingw 中的一个错误?

I can reproduce the same thing with VS2005.我可以用 VS2005 重现同样的东西。 The problem is that the compiler optimizes the catch away.问题是编译器优化了catch Why?为什么? Because according to the C++ standard it's undefined what happens if an extern "C" function exits with an exception.因为根据 C++ 标准,如果extern "C"函数异常退出,会发生什么情况是未定义的。 So the compiler assumes that SleepEx (which is extern "C" ) does not ever throw.所以编译器假定SleepEx (即extern "C" )永远不会抛出。 After inlining of Test::Test and Test::~Test it sees that the printf doesn't throw either, and consequently if something in this block exits via an exceptionTest::TestTest::~Test内联之后,它发现printf也没有抛出,因此如果这个块中的某些东西通过异常退出

    Test t("thread_test");

    SleepEx(INFINITE,true);

    return 0;

the behavior is undefined!行为未定义!

In MSVC the code doesn't work with the /EHsc switch in Release build, but works with /EHa or /EHs , which tell it to assume that C function may throw.在 MSVC 中,代码不适用于发布版本中的/EHsc开关,但适用于/EHa/EHs EHs ,这告诉它假设 C 函数可能会抛出异常。 Perhaps GCC has a similar flag.也许 GCC 有类似的标志。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM