2010-10-21 10 views
2

Pourquoi l'exemple de code ci-dessous entraîne-t-il un thread s'exécuter bien plus qu'un autre mais pas un mutex?Problème de section critique dans Windows 7

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

typedef struct _THREAD_INFO_ { 

    COORD coord;  // a structure containing x and y coordinates 
    INT threadNumber; // each thread has it's own number 
    INT count; 

}THREAD_INFO, * PTHREAD_INFO; 

void gotoxy(int x, int y); 

BOOL g_bRun; 
CRITICAL_SECTION g_cs; 

unsigned __stdcall ThreadFunc(void* pArguments) 
{ 
    PTHREAD_INFO info = (PTHREAD_INFO)pArguments; 

    while(g_bRun) 
    { 

     EnterCriticalSection(&g_cs); 

     //if(TryEnterCriticalSection(&g_cs)) 
     //{ 
      gotoxy(info->coord.X, info->coord.Y); 
      cout << "T" << info->threadNumber << ": " << info->count; 

      info->count++; 

      LeaveCriticalSection(&g_cs); 

     //} 
    } 

    ExitThread(0); 
    return 0; 
} 

int main(void) 
{ 
    // OR unsigned int 
    unsigned int id0, id1; // a place to store the thread ID returned from CreateThread 
    HANDLE h0, h1; // handles to theads 

    THREAD_INFO tInfo[2]; // only one of these - not optimal! 

    g_bRun = TRUE; 

    ZeroMemory(&tInfo, sizeof(tInfo)); // win32 function - memset(&buffer, 0, sizeof(buffer)) 

    InitializeCriticalSection(&g_cs); 

    // setup data for the first thread 
    tInfo[0].threadNumber = 1; 
    tInfo[0].coord.X = 0; 
    tInfo[0].coord.Y = 0; 

    h0 = (HANDLE)_beginthreadex( 
      NULL,  // no security attributes 
      0,   // defaut stack size 
      &ThreadFunc, // pointer to function 
      &tInfo[0], // each thread gets its own data to output 
      0,   // 0 for running or CREATE_SUSPENDED 
      &id0); // return thread id - reused here 

    // setup data for the second thread 
    tInfo[1].threadNumber = 2; 
    tInfo[1].coord.X = 15; 
    tInfo[1].coord.Y = 0; 

    h1 = (HANDLE)_beginthreadex( 
      NULL,  // no security attributes 
      0,   // defaut stack size 
      &ThreadFunc, // pointer to function 
      &tInfo[1], // each thread gets its own data to output 
      0,   // 0 for running or CREATE_SUSPENDED 
      &id1); // return thread id - reused here 

    _getch(); 

    g_bRun = FALSE; 

    return 0; 
} 

void gotoxy(int x, int y) // x=column position and y=row position 
{ 
    HANDLE hdl; 
    COORD coords; 
    hdl = GetStdHandle(STD_OUTPUT_HANDLE); 
    coords.X = x; 
    coords.Y = y;  
    SetConsoleCursorPosition(hdl, coords); 
} 

Répondre

0

En termes de main wavey:

CriticalSection dit le fil veut le contrôle de faire des choses ensemble. Mutex est en train de faire un marqueur pour montrer qu'il est 'occupé' afin que les autres puissent attendre et notifier l'achèvement pour que quelqu'un d'autre puisse commencer. Quelqu'un d'autre qui attend déjà le mutex l'attrapera avant de pouvoir recommencer la boucle et de la récupérer.

Donc ce que vous obtenez avec CriticalSection est un échec à céder entre les boucles. Vous pourriez voir une différence si vous aviez Sleep(0); après LeaveCriticalSection

0

Je ne peux pas dire pourquoi vous observez ce comportement particulier, mais c'est probablement à voir avec les spécificités de la mise en œuvre de chaque mécanisme. Ce que je peux dire, c'est que déverrouiller puis bloquer immédiatement un mutex est une mauvaise chose. Vous observerez éventuellement un comportement étrange.

3

Cela peut ne pas répondre à votre question, mais le comportement des sections critiques a changé sur Windows Server 2003 SP1 et versions ultérieures.

Si vous avez des bogues liés à des sections critiques de Windows 7 que vous ne pouvez pas reproduire sur un ordinateur XP, vous risquez d'être affecté par ce changement. D'après ce que je comprends, sous Windows XP, les sections critiques utilisaient une stratégie FIFO équitable pour tous les threads, tandis que les versions ultérieures utilisaient une nouvelle stratégie visant à réduire le changement de contexte entre les threads.

Il y a une courte note à ce sujet sur le MSDN page about critical sections

Vous pouvez également consulter this forum post

+0

Merci. Le message du forum semble répondre à la question. La conclusion semble être qu'une section critique n'est pas un bon moyen de partager une ressource comme un fichier journal, etc. – user483504

+1

Ce n'est pas une conclusion correcte. Une section critique devrait être parfaitement bien. Tant que la bande passante du disque est supérieure à la vitesse d'écriture des fichiers journaux, tous les threads seront finalement pris en charge. Lorsque le taux total d'écritures dépasse la bande passante du disque, vous avez plus de problèmes que la programmation injuste. – MSalters

0

de certains docs MSDN (http://msdn.microsoft.com/en-us/library/ms682530.aspx):

À partir de Windows Server 2003 avec Service Pack 1 (SP1), les threads en attente sur une section critique n'acquièrent pas la section critique sur le principe du premier arrivé, premier servi. Cette modification augmente les performances de façon significative pour la plupart des codes

+0

Le code fonctionne bien sur XP mais pas sur 7 sur le même matériel. Dans le code montré, un thread domine généralement et l'autre thread s'exécute toutes les quelques secondes. Il est également intéressant de noter que SRW se comporte de la même manière. – user483504

2

Les sections critiques, comme les mutex, sont conçues pour protéger une ressource partagée contre les accès conflictuels (tels que les modifications simultanées). Les sections critiques sont et non destinée à remplacer la priorité des threads.

Vous avez artificiellement introduit une ressource partagée (l'écran) et l'avez transformé en un goulot d'étranglement. En conséquence, la section critique est fortement contestée. Puisque les deux threads ont la même priorité, ce n'est pas une raison pour que Windows préfère un thread plutôt qu'un autre. La réduction des changements de contexte est une raison de choisir un fil sur un autre. À la suite de cette réduction, l'utilisation de la ressource partagée augmente. C'est une bonne chose; cela signifie qu'un thread sera terminé un lot plus tôt et l'autre thread finira un peu plus tôt.

Pour voir l'effet graphique, comparer

A B A B A B A B A B 

à

AAAAA BBBBB 

La deuxième séquence est plus courte parce qu'il n'y a qu'un seul passage de A à B.

Questions connexes