【问题标题】:Strange crash with C++ atexit() functionC++ atexit() 函数的奇怪崩溃
【发布时间】:2014-05-10 18:21:04
【问题描述】:

我在 Visual Studio 2013 中使用 MSVC。这是我正在编译的代码:

#include <iostream>
using namespace std;

void crash()
{
    cout << "crash?" << endl;
    system("PAUSE");
}

int main(int argc, char *argv[])
{
    atexit(crash);
    //while(true);
    return 0;
}

现在的方式 - 它就像一个魅力。我启动程序,它进入崩溃功能,暂停,我按下一个键,它正常关闭。都很酷。但是,如果我取消注释 while 循环并使用控制台上的 X 按钮将其关闭,我会在 endl 函数中崩溃。我能够确定崩溃是由 _Ostr.widen() 这是MSVC提供的endl函数的实现:

template<class _Elem,
    class _Traits> inline
    basic_ostream<_Elem, _Traits>&
        __CLRCALL_OR_CDECL endl(basic_ostream<_Elem, _Traits>& _Ostr)
    {   // insert newline and flush stream
    _Ostr.put(_Ostr.widen('\n'));
    _Ostr.flush();
    return (_Ostr);
    }

使用 Ctrl+C 终止程序会产生相同的效果。我该如何解决这个问题?

【问题讨论】:

  • 在调用atexit 时,标准输出的句柄可能不再有效。
  • @chris 如果我只是跳过 '
  • 可能是因为endl 刷新了流。
  • 在异常状态下启动另一个分叉进程也可能是一个相当糟糕的主意!
  • 好吧,拉起VS后,看起来是widen调用。花了两秒钟告诉它调试,locale 复制构造函数在_Ptr-&gt;Incref(); 上崩溃。

标签: c++ crash cout ostream atexit


【解决方案1】:

看来我的怀疑是真的。我像这样修改了代码:

#include <iostream>
using namespace std;

#include <Windows.h>

void crash()
{
    printf("%i\n", GetCurrentThreadId());
    system("PAUSE");
}

int main()
{
    printf("%i\n", GetCurrentThreadId());

    atexit(crash);
    //while(true);

    return 0;
}

当程序正常存在时,两个 printf()s 显示相同的线程 ID,但是当我按 Ctrl+C 或 X 按钮时,线程 ID 不同,这解释了崩溃并且当你考虑它时很有意义.因此,这里有一个如何解决这个问题的小例子:

#include <iostream>
#include <conio.h>
using namespace std;

#include <Windows.h>

volatile bool wantClose = false;

void OnExit()
{
    cout << GetCurrentThreadId() << endl;
    system("PAUSE");
}

BOOL WINAPI OnConsoleClose(DWORD dwCtrlType)
{
    wantClose = true; // set a flag that the console wants us to close
    ExitThread(0); // kill this thread immediately so it doesn't make the console stuck
    return FALSE;
}

int main()
{
    cout << GetCurrentThreadId() << endl;

    SetConsoleCtrlHandler(OnConsoleClose, TRUE); // handle close requests from the console
    atexit(OnExit);
    while(!wantClose); // at some point in our code we will have to check whether the console wants us to close down

    return 0;
}

请注意:使用 system("PAUSE") 和忙等待只是为了保持示例简单。我建议在实际代码中使用它们。

【讨论】:

  • 你需要volatile,你现在拥有的是未定义的行为。
  • @BenVoigt 已更正。谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-11-16
  • 2019-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-01
  • 2023-02-02
相关资源
最近更新 更多