2010-07-20 3 views
5

J'ai un programme très compliqué qui échoue, et je l'ai simplifié à cet ensemble de test avec un fichier batch et un programme C.Pourquoi ne puis-je pas tester le code retour sous Windows 7?

Mon programme C utilise ExitProcess pour renvoyer le niveau d'erreur à un fichier de traitement par lots. Parfois, sur Windows 7 (Microsoft Windows [Version 6.1.7600]), le niveau d'erreur n'est pas interprété correctement.

Je pense que cela devrait fonctionner pour toujours. Sous Windows XP, il semble fonctionner éternellement. Sur deux machines Windows 7 dual-core différentes (une 64-bit 32 bits) il échoue en quelques minutes.

Je ne peux pas imaginer que je fasse quelque chose de mal, mais au cas où il y aurait quelque chose d'amusant à propos de ExitProcess sur Windows 7, j'ai pensé que je demanderais. Y a-t-il quelque chose que j'ai fait illégalement?

fichier batch pour test.bat 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 

Programme 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); 
    } 

Ma version du compilateur et appel sont:

Microsoft (R) Compilateur d'optimisation C/C++ 32 bits Version 12.00.8804 pour 80 x 86

Droit d'auteur (C) Microsoft Corp 1984-1998. Tous les droits sont réservés.

cl/MT level250.c

Autres informations: J'ai également essayé de courir sous TCC JPSoft et obtenir le même comportement que l'utilisation de CMD. J'utilise un programme .c droit, pas .cpp. Je ne vois aucun échec dans une seule version filetée. Je mets les sources et les binaires sur http://jcook.info/win7fail et le fichier zip MD5 est 579F4FB15FC7C1EA454E30FDEF97C16B et CRC32 est C27CB73D.

EDIT Après des suggestions, j'ai encore modifié le cas de test et toujours voir les échecs. Dans notre application actuelle, il y a des centaines de threads. Certains threads sortent avec divers codes de retour significatifs, certains sont exécutés pour toujours et certains sont bloqués dans les appels du système d'exploitation ou les DLL et sont difficiles (voire impossibles) à tuer.

#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

Si vous n'attendez pas l'ajout de votre thread une fois celui-ci terminé avant d'appeler ExitProcess()? – IanNorton

+0

Vous devriez utiliser WaitForSingleObject() au lieu d'une boucle occupée pour attendre la fin du thread. En outre, renvoyez simplement 250 de WinMain() au lieu d'appeler directement ExitProcess(). Le code de démarrage du compilateur appellera ExitProcess() après la fermeture de WinMain(). –

+0

@IanNorton: Je ne crois pas qu'il soit nécessaire d'attendre que les threads se terminent et/ou se rejoignent. Notre programme entier a des threads qui ne peuvent pas se terminer, soit en raison d'E/S bloquées ou d'appels système ou d'autres raisons. Y a-t-il une documentation de Microsoft sur laquelle vous pouvez me diriger et qui montre les exigences pour rejoindre des threads? @Remy: Notre programme actuel est beaucoup plus compliqué et il y a une raison pour le test direct. Comme il s'avère, supprimer toute mention de la variable Terminate ne résout pas le problème. c'est-à-dire un thread qui revient simplement et un WinMain qui crée le thread puis quitte échoue également. – piCookie

Répondre

1

Imprimer ce que le code de retour fait est. Il n'y a aucune garantie que si quelque chose ne va pas, vous obtiendrez les 251 et 250 que vous attendez, comme une erreur de segmentation ou d'autres erreurs dont vous n'êtes pas conscient. En outre, je ne peux pas voir où vous retournez 251 dans votre code. Méfiez-vous des codes de sortie élevés, je crois 255 est limite portable, sur certains systèmes il peut être inférieur à 64, ou < = 127. (Cela peut être hors de propos vu que vous utilisez évidemment Windows, mais il vaut la peine de noter.)

Essayez également d'invoquer un débogueur ou de charger un core dump lors de la mort inattendue du processus.

+0

Dans un fichier de traitement par lots "si errorlevel 251" exécute l'action si le niveau d'erreur est de 251 ou plus. Par conséquent, avec "if errorlevel 250" est le moyen de tester exactement 250. Nous avons toutes sortes de manipulation pour segfault et autres, mais j'ai réduit un problème de plusieurs milliers de lignes à ce cas simple, espérant apprendre pourquoi simple cas échoue. – piCookie

1

Il semble retourner le résultat du thread dans les temps où il échoue. J'ai changé la valeur de retour du fil à 37 et ajouté echo %errorlevel% à la fin du fichier de commandes. Quand il s'est arrêté sur mon PC, il a imprimé 37. Donc il semble qu'il y ait une sorte de problème de synchronisation.Pour résoudre ce problème, je l'ai changé le code principal à ce qui suit:

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

La documentation ExitProcess dit clairement que le code de sortie est « pour le processus et toutes les discussions ». Donc, il semblerait qu'il y ait un bug, cependant, s'appuyer sur ExitProcess pour tuer tous les threads ne semble pas être le meilleur plan. Donc, attendre leur fin est probablement une ligne de conduite raisonnable.

J'ai construit le programme et reproduit le problème avec VC6 (la version que vous avez utilisé je crois), VS2005, et VS2008. Je l'ai couru, par curiosité, sur un ordinateur portable win7 à 2 cœurs et un ordinateur de bureau win7 à 4 cœurs. Il ne se reproduisait pas sur une machine XP hyperthreaded plus ancienne, mais cela ne veut pas dire que ça ne finirait pas par échouer; peut-être qu'il fallait juste courir plus longtemps là-bas. Ce serait un peu de kludge, mais peut-être une solution de contournement serait de stocker le code de sortie dans une variable globale dans l'application et de renvoyer cette valeur de tous les threads. Ensuite, dans la situation où ce problème/bug se produit, le code de sortie de l'application serait toujours la valeur souhaitée.

+0

Merci beaucoup pour vos efforts! Malheureusement, nous ne pouvons pas attendre que les threads se terminent dans notre programme actuel (certains sont bloqués dans le système d'exploitation, etc.) mais je vais explorer davantage les choses à faire avant d'appeler ExitProcess. Notre programme a fonctionné pendant des années sur Windows NT 4.0 et sans jamais avoir un échec errorlevel comme ceci; Je soupçonne que votre machine XP n'échouera jamais. – piCookie

+0

Hélas, votre edit kludge n'est pas non plus utilisable dans notre application live car certains threads qui se terminent transmettent des informations dans leur valeur de retour. Merci pour vos idées continues! – piCookie

+0

@piCookie: Le monde réel conspire contre les solutions faciles :) Je pense que vous avez raison de dire que c'est spécifiquement un problème Win7. Ou au moins je suis incapable de te prouver le contraire. Je laisse passer plus d'un demi-million d'itérations sur une machine XP à deux cœurs sans défaillance. C'est un problème intéressant (plus pour moi que pour vous j'en suis sûr car ce n'est pas mon problème direct). –

Questions connexes