Problème Windows WriteFile lors de l’utilisation de threads

Mon entreprise développe un matériel qui doit communiquer avec les logiciels. Pour ce faire, nous avons créé un pilote permettant d’écrire et de lire du matériel. Pour accéder au pilote, nous utilisons la commande:

HANDLE device = CreateFile(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0x00000007, &sec, OPEN_EXISTING, 0, NULL); 

La lecture et l’écriture se font à l’aide des fonctions:

 WriteFile(device,&package,package.datasize,&bytesWritten,NULL); 

et

 ReadFile(device,returndata,returndatasize,&bytesRead,NULL); 

Et enfin, CloseHandle (device), pour fermer le fichier.

Cela fonctionne très bien dans le cas où les fonctions sont appelées à partir du thread principal. Si elles sont appelées à partir d’un autre thread, nous obtenons l’erreur 998 (no_acccess) lorsque vous essayez d’écrire plusieurs éléments. Les threads sont créés en utilisant

 CreateThread(NULL, 0, thread_func, NULL, 0, &thread_id); 

Je suis à court d’idées ici, des suggestions?

edit: Lors de l’exécution de la séquence suivante:

 Main_thread: CreateFile Write Close CreateThread WaitForThread Thread_B: CreateFile Write Close 

Main_Thread réussit et Thread_B ne le fait pas. Cependant, lorsque vous écrivez de petits ensembles de données, cela fonctionne bien. Est-ce que cela peut être dû au fait que Thread_B n’hérite pas de tous les privilèges d’access de Main_Thread?

edit2: beaucoup de bonne reflection se passe ici, très apprécié! Après quelques travaux sur ce problème, il semble que ce soit le cas:

L’api contient un thread de queue, gérant tous les paquets allant et venant du périphérique. Ce thread gère les pointeurs vers les objects-packages. Lorsqu’un pointeur atteint l’avant de la queue, une fonction “send_and_get” est appelée. Si les tableaux du package sont alloués dans le même thread qui appelle la fonction “send_and_get”, tout fonctionne correctement. Si les tableaux sont alloués dans un autre thread, l’envoi échoue. Comment résoudre ce problème, cependant, je ne sais pas.

Selon winerror, l’erreur 998 de Win32 est l’une des valeurs d’état natives suivantes (qui seraient renvoyées par le système d’exploitation ou le pilote):

  998 ERROR_NOACCESS <--> 0x80000002 STATUS_DATATYPE_MISALIGNMENT 998 ERROR_NOACCESS <--> 0xc0000005 STATUS_ACCESS_VIOLATION 998 ERROR_NOACCESS <--> 0xc00002c5 STATUS_DATATYPE_MISALIGNMENT_ERROR 

La violation d’access peut être un candidat probable selon que vous dites “lorsque vous essayez d’écrire plus de deux éléments”. Êtes-vous sûr que le tampon que vous envoyez est assez grand?

Les erreurs d’alignement sont assez exotiques, mais peuvent être pertinentes si le périphérique a des exigences d’alignement et que le développeur a choisi d’utiliser ces erreurs particulières.

-scott

Cela me semble toujours comme un access simultané. Vos threads distincts écrivant sur ce périphérique devront protéger correctement l’access au fichier en utilisant un mutex ou similaire. Ouvrez la poignée dans le thread principal et laissez-la ouverte ou protégez toute la séquence Open -> Write -> Close qui peut apparaître dans chaque thread (avec un mutex).

En tant que mesure de débogage, étant donné qu’il s’agit de votre propre pilote, vous pouvez demander au pilote de consigner les demandes qu’il reçoit, par exemple dans le journal des événements. Configurez deux séries de tests identiques, à ceci près que l’un exécute tout le code dans le thread principal et que l’autre exécute tout le code dans un second thread. La comparaison des résultats devrait vous donner une meilleure idée de ce qui se passe.

Il serait également judicieux de demander à votre pilote de signaler tout code d’erreur renvoyé au système d’exploitation.

La première chose à vérifier est si l’erreur (998) signalée par votre pilote ou par le gestionnaire d’E / S en mode kernel (qui est chargé d’initier l’IRP et d’appeler votre pilote) avant même que la requête parvienne à votre pilote. Vous devriez être en mesure de le découvrir car ceci est votre pilote. Il suffit de consigner les appels à la routine Dispatch du pilote, ce qu’il renvoie, ce qu’il fait (appelle-t-il d’autres pilotes ou appelle IoCompleteRequest avec un code d’erreur ou etc.) et les choses doivent devenir claires.

Dans le scénario que vous décrivez, il semble que l’erreur soit probablement due à votre pilote. Par exemple, votre pilote peut allouer une structure d’état globale à une réponse à CreateFile (qui est le pilote IRP_MJ_CREATE ) et le purger lorsque le fichier est fermé. Un tel pilote ne fonctionnera pas correctement si deux fichiers sont ouverts simultanément, alors un est fermé alors que le second reçoit toujours des requêtes d’E / S.