C++/pthread/join 错误消息的含义 "what(): Invalid argument"

Meaning of C++/pthread/join error message "what(): Invalid argument"

本文关键字:what Invalid argument join pthread 错误 消息 C++      更新时间:2023-10-16

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

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(),则可能会显示以下不稳定的错误消息:

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

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

在我的特殊情况下,由于线程已经连接,因此引发了异常。在加入之前检查可加入。

某些东西抛出std::system_error的可能原因(用EINVAL,像这里一样,或者用其他一些值)是很多的。

您可以:

  1. Google 上 cppreference.com 上的std::system_error实例,或
  2. 指示调试器在抛出时中断,然后您可以确切地看到导致引发异常的原因 - 然后转到该内容的文档并阅读它为什么会抛出。

这些信息本身并不神秘,它们只是间接归功于整个C++生态系统的运作方式。它是否可以设计为调用一些特定的"终止"函数,仅在您忘记加入线程的情况下保留?确定。

但这真的很笨拙,增加了运行时模块的大小,并没有真正的任何收益。随着你编写更多的代码,你将获得经验,并开始记住或"感觉"什么样的事情会导致什么样的问题。多线程代码中有关std::system_errorstd::terminate的任何内容几乎可以肯定与所述线程的不当处理有关。过一会儿你就会知道了。

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

终止调用而不显示活动异常

直接叫std::terminate的东西。同样,您可以在库文档中搜索此语句,并找出与代码相关的可能原因。

在抛出"std::system_error"实例后终止调用

抛出了一个异常,但你的程序中没有捕获它的try/catch,所以std::terminate是由异常系统调用的。同样,您可以研究您使用的哪些功能可能会抛出std::system_error,还可以考虑在代码中添加一些异常安全性。

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

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

  1. 使代码检测这些违反其接口要求的冲突,以便可以轻松查找和修复它们。这在这里很容易。unspin函数可以resetshared_ptrspin功能可以检查shared_ptr是否未就位。

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

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

这也使代码可维护。如果有人想要重新实现此代码、添加功能或优化它,他们可以使用单元测试来确保他们没有破坏其他代码预期依赖的任何行为。