2010-07-20 4 views
5

Tengo un programa muy complicado que está fallando, y lo he simplificado para este conjunto de prueba con un archivo por lotes y un programa C.¿Por qué no puedo probar el código de retorno en Windows 7?

Mi programa C usa ExitProcess para devolver el errorlevel a un archivo por lotes. En ocasiones, en Windows 7 (Microsoft Windows [Versión 6.1.7600]), el nivel de error no se interpreta correctamente.

Creo que esto debería funcionar para siempre. En Windows XP, parece ejecutarse para siempre. En dos máquinas diferentes de Windows 7 de doble núcleo (una de 64 bits y otra de 32 bits) falla en un par de minutos.

No me puedo imaginar que estoy haciendo algo mal, pero en caso de que haya algo gracioso sobre ExitProcess en Windows 7, pensé en preguntar. ¿Hay algo aquí que he hecho ilegalmente?

por lotes de archivos test.bat para cmd.exe:

@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 

Programa level250.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); 
    } 

Mi versión del compilador y la invocación son:

Microsoft (R) Versión del compilador de optimización C/C++ 32-bit 12.00.8804 para 80x86

Copyright (C) Microsoft Corp 1984-1998. Todos los derechos reservados.

cl level250.c/MT

Información adicional: También he intentado correr bajo TCC de JPSoft y obtener el mismo comportamiento que el uso de CMD. Estoy usando un programa .c directo, no .cpp. No veo fallas en una sola versión con hilos. Puse las fuentes y los binarios en http://jcook.info/win7fail y el archivo zip MD5 es 579F4FB15FC7C1EA454E30FDEF97C16B y CRC32 es C27CB73D.

EDIT Después de las sugerencias, he cambiado aún más el caso de prueba y todavía veo los fallos. En nuestra aplicación real, hay cientos de hilos. Algunos subprocesos salen con varios códigos de retorno significativos, algunos se ejecutan para siempre, y otros se cuelgan en llamadas al sistema operativo o DLL y son difíciles (si no imposibles) de matar.

#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); 
    } 
+1

¿No debería estar esperando la unión de su hilo una vez que se completa antes de llamar a ExitProcess()? – IanNorton

+0

Debería utilizar WaitForSingleObject() en lugar de un bucle ocupado para esperar la terminación de la secuencia. Además, simplemente devuelva 250 desde WinMain() en lugar de llamar a ExitProcess() directamente. El código de inicio del compilador llamará a ExitProcess() después de que salga WinMain(). –

+0

@IanNorton: no creo que sea necesario esperar a que los hilos terminen y/o se unan. Nuestro programa completo tiene algunos subprocesos que no pueden finalizar, ya sea debido a llamadas de sistema o E/S bloqueadas u otras razones. ¿Hay alguna documentación de Microsoft a la que me puede dirigir que muestre los requisitos para volver a unir los hilos? @Remy: Nuestro programa real es mucho más complicado y hay una razón para la prueba directa. Como resultado, eliminar toda mención de la variable Terminate no resuelve el problema. Es decir, un hilo que simplemente retorna y un WinMain que crea el hilo y luego sale también falla. – piCookie

Respuesta

1

Imprimir lo que el código de retorno realidad es. No hay garantía de que si algo sale mal, obtendrá el 251 y el 250 que espera, como por error de segmentación u otros errores de los que no tenga conocimiento. Además, no puedo ver dónde estás devolviendo 251 en tu código. Tenga cuidado con los códigos de salida altos, creo que 255 es un límite portátil seguro, en algunos sistemas puede ser menor que 64 o < = 127. (Esto podría ser irrelevante ya que obviamente está usando Windows, pero vale la pena señalarlo)

También intente invocar un depurador o cargar un volcado de memoria en el proceso de muerte inesperada.

+0

En un archivo por lotes "if errorlevel 251" realiza la acción si el nivel de error es 251 o más. Por lo tanto, seguir con "if errorlevel 250" es la forma de probar exactamente 250. Tenemos todo tipo de manejo para segfault y demás, pero he reducido un problema de varias mil líneas a este caso simple, esperando aprender por qué este simple caso falla – piCookie

1

Parece que está devolviendo el resultado del hilo en los momentos en que falla. Cambié el valor de retorno del subproceso a 37 y agregué echo %errorlevel% al final del archivo por lotes. Cuando se detuvo en mi PC, imprimió 37. Parece que hay algún tipo de problema de sincronización.Para solucionarlo, he cambiado el código principal a la siguiente:

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

La documentación para ExitProcess dice claramente que el código de salida es "para el proceso y todas las discusiones". Entonces parece que hay un error, sin embargo, confiar en ExitProcess para matar todos los hilos no parece ser el mejor plan. Entonces, esperar que ellos terminen es probablemente un curso de acción razonable.

Creé el programa y reproduje el problema con VC6 (la versión que usé creo), VS2005 y VS2008. Lo ejecuté, por curiosidad, en una computadora portátil win7 de 2 núcleos y una máquina de escritorio win7 de 4 núcleos. No se reprodujo en una antigua máquina XP de un solo núcleo con hiperfrecuencia, pero eso no quiere decir que finalmente no fallaría; tal vez solo necesitaba correr más tiempo allí.

Editar Sería un poco dudoso, pero quizás una solución sería almacenar el código de salida en una variable global en la aplicación y devolver ese valor de todos los hilos. Luego, en la situación donde ocurre este problema/error, el código de salida de la aplicación seguirá siendo el valor deseado.

+0

¡Muchas gracias por sus esfuerzos! Lamentablemente, no podemos esperar a que los hilos terminen en nuestro programa real (algunos se cuelgan en el sistema operativo, etc.), pero exploraré más cosas sobre qué hacer antes de llamar a ExitProcess. Nuestro programa se ha ejecutado durante años en Windows NT 4.0 y en adelante sin tener una falla de nivel de error como esta; Sospecho que tu máquina XP nunca fallará. – piCookie

+0

Por desgracia, su edición de kludge tampoco funciona en nuestra aplicación en vivo porque algunos subprocesos que finalizan devuelven información en su valor de retorno. Gracias por tus ideas continuas! – piCookie

+0

@piCookie: el mundo real conspira contra las soluciones fáciles :) Creo que tienes razón en que es específicamente un problema de Win7. O al menos no puedo probar que estás equivocado. Dejé que ejecutara más de medio millón de iteraciones en una máquina XP de dos núcleos sin fallas. Es un problema interesante (más para mí que tú, estoy seguro, ya que no es mi problema directo). –

Cuestiones relacionadas