【问题标题】:Unable to catch std::invalid_argument无法捕获 std::invalid_argument
【发布时间】:2009-09-04 08:02:17
【问题描述】:

我遇到了一个我无法追踪的 std::invalid_argument 异常问题。我正在使用 gcc 4.4.0 (windows)、pthreads-win32 2.8.0 和 GC2 dll。

基本上,从两个线程(主线程和一个使用 pthread_create 启动的线程),我尝试大致同时创建一个类 A 的实例。构造函数抛出一个 std::invalid_argument,但它被应该捕获异常的 try/catch 块包围。然而,这并没有发生(很少,只有一个线程可能会捕获异常 - 但没有关于哪个线程会这样做的规则)

如果我尝试仅在其中一个线程上创建对象,则创建会正常工作,并且会捕获异常。如果我在不同时间创建这两个对象,则创建会正常工作并且会捕获异常。如果我尝试同时创建它们,会调用 ::terminate()。

也许有人知道为什么会发生这种情况(我已排除标题):

void *run(void *ptr)
{
    Sleep(5000);
    try
    {
        A *a = new A(5);
        a->a = 12;
    }
    catch (std::exception &ex)
    {
        printf("t - %s\n", ex.what());
    }
    return NULL;
}

int main(void) {
    pthread_t t;
    if (pthread_create(&t, NULL, run, NULL) != 0)
    {
        printf("No thread\n");
    }
    else
    {
        Sleep(5000);
        try
        {
            A *a = new A(5);
            a->a = 13;
        } catch (std::exception &ex)
        {
            printf("M - %s\n", ex.what());
        }
        pthread_join(t, NULL);
    }
    return 0;
}

class A
{
public:
    A(int a);
    virtual ~A();
    int a;
};
A::A(int a)
{
    throw std::invalid_argument("Invalid!");
}
A::~A(){}

makefile 是:

CXXFLAGS = -O0 -g -Wall -Werror -fmessage-length=0
OBJS =  WOpenTest.o A.o
INCL = -I../pthreads-win32/include 
LIBS =   -lws2_32 -lgdi32 -lpthreadGC2 
LIB_DIRS =  -L ../pthreads-win32/lib 
TARGET = WOpenTest.exe
$(TARGET): $(OBJS)
 $(CXX) -o $(TARGET) $(OBJS) $(LIBS) $(LIB_DIRS) $(INCL)
WOpenTest.o : WOpenTest.cpp
 g++ $(CXXFLAGS) -c WOpenTest.cpp $(INCL)  
A.o : A.cpp A.h
 g++ $(CXXFLAGS) -c A.cpp $(INCL)
all: $(TARGET)
clean:
 rm -f $(OBJS) $(TARGET)

我看到的输出是:

(最频繁)$ ./WOpenTest.exe

此应用程序已请求 运行时以异常终止它 方法。请联系应用程序的 支持团队了解更多信息。

此应用程序已请求 运行时以异常终止它 方法。请联系应用程序的 支持团队了解更多信息。 抛出一个终止后调用 'std::invalid_argument' 的实例 递归调用终止

$ ./WOpenTest.exe

此应用程序已请求 运行时以异常终止它 方法。请联系应用程序的 支持团队了解更多信息。 M - 无效!

$ ./WOpenTest.exe

此应用程序已请求 运行时以异常终止它 方法。请联系应用程序的 支持团队了解更多信息。 t - 无效!

此应用程序已请求 运行时以异常终止它 方法。请联系应用程序的 支持团队了解更多信息。

此应用程序已请求 运行时以异常终止它 方法。请联系应用程序的 支持团队了解更多信息。 抛出一个终止后调用 “std::invalid_argument”的实例
what(): 无效!

关于我应该做什么而我不做什么有什么想法吗?还是我在 pthreads 中缺少的东西?

【问题讨论】:

  • 我找到了答案,归结为 mingw msvcrt 不是线程安全的。

标签: c++ exception error-handling


【解决方案1】:

您已经得出结论,这与 MinGW 链接到的单线程库有关。我找到了一个关于 configuring NetBeans to use MinGW 的页面,它在“使用 Posix 线程的多线程”部分下有以下建议:

  • 使用异常处理时的重要提示:使用附加的编译器开关“-mthreads”编译您的应用程序。否则异常处理将无法可靠地工作,并且可能会发生非特定的崩溃。将异常从 DLL 传播到应用程序时可能会出现其他问题。我在网上找到了一些关于这个的提示,但是没有经验,因为我的 DLL 不会抛出异常。

GCC documentation 中也描述了 x86 选项:

-mthreads

支持“Mingw32”上的线程安全异常处理。依赖线程安全异常处理的代码必须使用-mthreads 选项编译和链接所有代码。编译时-mthreads定义-D_MT;链接时,它会链接到一个特殊的线程助手库-lmingwthrd,它会清理每个线程的异常处理数据。

请在编写自己的线程安全异常之前尝试一下。

【讨论】:

  • 感谢您的回答。我已经编译并与 -mthreads 链接:运行时错误仍然出现,尽管不像以前那样频繁。然而,“不那么频繁”还不够好,所以现在我必须继续处理线程安全异常。我想我遗漏了一些东西,但是在查看了所有 gcc 选项后,我无法确定那是什么
【解决方案2】:

在此处发布最终答案,以防将来有人查找。该问题是 gcc 4.4 中的一个严重错误:

http://n2.nabble.com/gcc-4-4-multi-threaded-exception-handling-thread-specifier-not-working-td3440749.html

【讨论】:

  • 该链接似乎不再有效。出于好奇,libstdc++ 是如何链接到您的应用程序的?它是静态完成的还是动态完成的?我遇到了与 mingw-gcc4.5.2 类似的问题,但前提是我动态链接 libstdc++6.dll
  • 这是不久前的事了。我认为mingw-users.1079350.n2.nabble.com/… 是一回事,但它只是一个快速的谷歌搜索。
【解决方案3】:

尝试使用pthreadGCE2 而不是pthreadGC2 进行链接。

【讨论】:

  • 我试过这样做(忘了提),它什么也没做。据我了解,两个版本之间的区别在于它们如何处理线程退出/取消 - 我不知道这是否会对这个测试用例产生影响
【解决方案4】:

我看不出有什么问题。

尝试添加一个 catch(...) 以查看是否发生了其他奇怪的事情。
如果异常从线程中逃脱(即 run()),那么 pthreads 将终止应用程序。但我看不到发生了什么。

顺便说一句:
尝试通过 const 引用捕获异常。

【讨论】:

  • 它也逃脱了 catch(...) ,因为 mingw 存在问题 - 抛出异常不是线程安全的。这种情况下的解决方案似乎是编写我自己的线程安全异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 2019-09-24
相关资源
最近更新 更多