C ++ / pthread / join错误消息“ what():无效参数”的含义

时间:2018-12-19 12:05:30

标签: c++ pthreads

它是一个较大的应用程序(一个简单的计时器线程)的一部分,该计时器线程在尝试完成之前可以正常工作:

boost::asio::io_service io_service;
shared_ptr<thread> loop;
// it is not initialised here, just shows the idea
boost::asio::deadline_timer timer(io_service, interval);

void Timer::spin() {
    loop = make_shared<thread>(&Timer::run, this);
}
void Timer::unspin() {
    io_service.stop();
    loop.get()->join();
}
void run() {
   timer.async_wait(bind(&Timer::callbackWrapper, this, _1));
   // restart
   io_service.run();    
}

spin中创建的线程在理论上终止并在unspin()中加入。如果应用程序以join()结尾的注释结束,则会出现错误消息

terminate called without an active exception

如果我对其进行了很好的“解密”,则意味着“当其他一些线程仍在运行时主线程完成”(我不知道C ++语言)。

如果依次调用unspin(),则可能显示以下 spotty 错误消息:

terminate called after throwing an instance of 'std::system_error'
  what():  Invalid argument

最有可能由thread.join()抛出。问题是,我在Stackexchange周围搜索,但无法解释其他消息。我意识到问题可能出在代码的小片段之外(应用程序相当大,因此我不包含它)。但是,即使是这样,我也只会询问第二条错误消息的含义及其可能原因。

编辑 David Schwartz发现了原始错误,连续两次调用unspin()。第二次尝试加入同一线程会产生问题消息。

3 个答案:

答案 0 :(得分:1)

在我的特定情况下,由于线程已经加入而引发了异常。加入之前请检查joinable

答案 1 :(得分:0)

抛出std::system_error(此处为EINVAL或具有其他值)的可能原因很多。

您可以:

  1. 在cppreference.com上使用Google搜索std::system_error的实例,或
  2. 指示调试器在引发异常时中断,然后您可以确切地了解导致异常引发的原因-然后转到该文档的文档中并了解其引发异常的原因。

这些消息本身并不是秘密的 ,由于整个C ++生态系统的工作方式,它们只是间接的。是否可以将其设计为调用某些特定的“终止”函数,该函数仅在您忘记加入线程的情况下保留?当然。

但这确实很笨拙,增加了运行时模块的大小,却并没有带来任何好处。随着编写更多代码,您将获得经验,并开始记住或“感觉”什么样的事情会引起什么样的问题。 几乎可以肯定与多线程代码中的std::system_errorstd::terminate有关,与对这些线程的不正确处理有关。不久之后,您就会知道。

在这种情况下,您可以记住以下两种解释:

  

在没有活动异常的情况下终止调用

Something直接调用了std::terminate。同样,您可以在图书馆文档中搜索有关此内容的说法,并找出与您的代码相关的可能原因。

  在抛出'std :: system_error'实例后调用

terminate

An exception was thrown,但是程序中没有捕获到它的try / catch,因此std::terminate被异常系统调用。同样,您可以研究正在使用的功能可以抛出std::system_error,还可以考虑在代码使用时为其添加一些异常安全性。

答案 2 :(得分:0)

当前形式的此代码无法进行合理的调试。这是因为它具有代码未检测到的接口规则(例如,连续两次不调用spin)。这使得代码很难测试,调试和维护。

它甚至会使代码难以理解,因为这些要求可能没有在代码或文本中的任何地方记录下来。对于未来:

  1. 使您的代码检测到此类违反其接口要求的行为,以便您可以轻松找到并修复它们。这很容易。 unspin函数可以reset shared_ptrspin函数可以检查shared_ptr是否未安装。

  2. 进行单元测试,以测试所有正确和错误的接口访问,因此您可以自己调试此代码,并确保正确检测错误的访问模式。其中一个单元测试应连续两次调用spin,并确保它返回正确的错误或引发正确的异常。这也可以作为代码,记录与类的接口一起起作用和不起作用的情况。

  3. 如果遇到无法解决的问题,则代码和单元测试可以单独显示该问题,并且您将确切知道代码的哪个方面失败。

    < / li>

这也使代码可维护。如果有人想重新实现此代码,添加功能或对其进行优化,则可以进行单元测试以确保他们不会破坏其他代码所期望的任何行为。