为什么我不能在Windows 7中测试返回码?

时间:2010-07-20 22:38:56

标签: c windows-7 batch-file

我有一个非常复杂的程序失败了,我用简化文件和C程序将它简化为这个测试集。

我的C程序使用ExitProcess将errorlevel传回一个批处理文件。有时在Windows 7(Microsoft Windows [Version 6.1.7600])上,错误级别无法正确解释。

我认为这应该永远存在。在Windows XP上,它似乎永远运行。在两台不同的双核Windows 7机器(一台64位,一台32位)上,它会在几分钟内发生故障。

我无法想象我做错了什么,但是如果在Windows 7上有一些关于ExitProcess的搞笑,我想我会问。这里有什么我非法做过的吗?

cmd.exe的批处理文件test.bat:

@ECHO OFF
SET I=0
:pass
SET /A I=I+1
Title %I%
start/wait level250
if errorlevel 251 goto fail
if errorlevel 250 goto pass
:fail

计划级别250.c:

#include "windows.h"

static volatile int Terminate = 0;

static unsigned __stdcall TestThread(void * unused)
    {
    Terminate = 1;
    return 0;
    }

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
    {
    CreateThread(NULL, 0, TestThread, NULL, 0, NULL);

    while (Terminate == 0) Sleep(1);
    ExitProcess(250);
    }

我的编译器版本和调用是:

  

Microsoft(R)32位C / C ++优化编译器版本12.00.8804 for 80x86

     

版权所有(C)Microsoft Corp 1984-1998。保留所有权利。

     

cl / MT level250.c

其他信息:我也尝试在JPSoft的TCC下运行,并获得与使用CMD相同的行为。我使用的是直接的.c程序,而不是.cpp。我没有在单线程版本中看到任何失败。我把源和二进制文件放在http://jcook.info/win7fail上,zip文件MD5是579F4FB15FC7C1EA454E30FDEF97C16B,CRC32是C27CB73D。

编辑经过建议,我进一步改变了测试用例并仍然看到了失败。在我们的实际应用中,有数百个线程。一些线程以各种重要的返回码退出,一些线程永远运行,一些线程挂在操作系统调用或dll中,并且很难(如果不是不可能)杀死。

#include "windows.h"

static unsigned __stdcall TestThread(void * unused)
    {
    return 0;
    }

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
    {
    CreateThread(NULL, 0, TestThread, NULL, 0, NULL);
    return(250);
    }

2 个答案:

答案 0 :(得分:1)

打印返回代码实际的内容。无法保证如果出现问题,您将获得所期望的251和250,例如通过分段错误或其他您不知道的错误。此外,我无法在您的代码中看到您返回251的位置。警惕高退出代码,我认为255是安全的可移植限制,在某些系统上它可能小于64,或者<= 127.(这可能无关紧要,因为你显然使用的是Windows,但值得注意。)

还尝试调用调试器,或在进程“意外死亡”时加载核心转储。

答案 1 :(得分:1)

它似乎在失败的时候返回线程的结果。我将线程的返回值更改为37,并将echo %errorlevel%添加到批处理文件的末尾。当它停在我的电脑上时,它打印了37.所以似乎存在某种同步问题。为了解决这个问题,我将main中的代码更改为以下内容:

HANDLE h = CreateThread(NULL, 0, TestThread, NULL, 0, NULL);
while (Terminate == 0) Sleep(1);
WaitForSingleObject( h, INFINITE );
ExitProcess(250);

ExitProcess的文档清楚地表明退出代码是“用于进程和所有线程”。所以似乎有一个bug,但是,依赖ExitProcess杀死所有线程似乎不是最好的计划。所以等待他们完成可能是一个合理的行动方案。

我构建了程序并用VC6(我相信你使用的版本),VS2005和VS2008重现了这个问题。出于好奇,我在2核win7笔记本电脑和4核win7台式机上运行它。它没有在旧的单核超线程XP机器上重现,但这并不是说它最终不会失败;也许它需要在那里跑得更久。

编辑这可能会有点麻烦,但也许一种解决方法是将退出代码存储在应用程序的全局变量中,并从所有线程返回该值。然后,在出现此问题/错误的情况下,应用程序的退出代码仍然是所需的值。