2010-06-06 5 views
2

Comment définir les données d'objet partagées entre threads et qui doivent être mises à jour une fois après le cycle complet de (disons) deux threads en boucle occupée?Partage d'un objet entre les threads

CRITICAL_SECTION critical_section_; 

int value; //needs to be updated once after the cycle of any number of threads running in busy loop 

void ThreadsFunction(int i) 
{ 

while (true) 
{ 
    EnterCriticalSection(&critical_section_); 
       /* Lines of Code */ 
    LeaveCriticalSection(&critical_section_); 
} 
} 

Modifier: Le value peut être un objet d'une classe.

Répondre

2

Deux suggestions:

  • rendre l'objet lui-même thread-safe.
  • passer l'objet dans le fil comme données d'instance

Je vais utiliser C++ comme référence dans mon exemple. Vous pouvez facilement transposer cela en C pur si vous le souhaitez.

// MyObject est les données de base que vous souhaitez partager entre les fils

struct MyObject 
{ 
    int value; 
    int othervalue; 
    // all all the other members you want here 
}; 


class MyThreadSafeObject 
{ 
private: 
    CRITICAL_SECTION _cs; 
    MyObject _myojbect; 
    bool _fLocked; 
public: 
    MyThreadSafeObject() 
    { 
     _fLocked = false 
     InitializeCriticalSection(); 
    } 
    ~MYThreadSafeObject() 
    { 
     DeleteCriticalSection(); 
    } 

    // add "getter and setter" methods for each member in MyObject 
    int SetValue(int x) 
    { 
     EnterCriticalSection(&_cs); 
      _myobject.value = x; 
     LeaveCriticalSection(&_cs); 
    } 

    int GetValue() 
    { 
     int x; 
     EnterCriticalSection(&_cs); 
      x = _myobject.value; 
     LeaveCriticalSection(&_cs); 
     return x; 
    } 

    // add "getter and setter" methods for each member in MyObject 
    int SetOtherValue(int x) 
    { 
     EnterCriticalSection(&_cs); 
      _myobject.othervalue = x; 
     LeaveCriticalSection(&_cs); 
    } 

    int GetOtherValue() 
    { 
     int x; 
     EnterCriticalSection(&_cs); 
      x = _myobject.othervalue; 
     LeaveCriticalSection(&_cs); 
     return x; 
    } 


    // and if you need to access the whole object directly without using a critsec lock on each variable access, add lock/unlock methods 
    bool Lock(MyObject** ppObject) 
    { 
     EnterCriticalSection(&_cs); 
     *ppObject = &_myobject; 
     _fLocked = true; 
     return true;     
    } 

    bool UnLock() 
    { 
     if (_fLocked == false) 
      return false; 

     _fLocked = false; 
     LeaveCriticalSection(); 
     return true; 
    } 
}; 

Ensuite, créez votre objet et le fil comme suit:

MyThreadSafeObject* pObjectThreadSafe; 
MyObject* pObject = NULL; 

// now initilaize your object 
pObjectThreadSafe->Lock(&pObject); 
    pObject->value = 0; // initailze value and all the other members of pObject to what you want them to be. 
    pObject->othervalue = 0; 
pObjectThreadSafe->Unlock(); 
pObject = NULL; 


// Create your threads, passing the pointer to MyThreadSafeObject as your instance data 
DWORD dwThreadID = 0; 
HANDLE hThread = CreateThread(NULL, NULL, ThreadRoutine, pObjectThreadSafe, 0, &dwThreadID); 


And your thread will operate as follows 
DWORD __stdcall ThreadFunction(void* pData) 
{ 
    MyThreadSafeObject* pObjectThreadSafe = (MyThreadSafeObject*)pData; 
    MyObject* pObject = NULL; 

    while (true) 
    { 
     /* lines of code */ 
      pObjectThreadSafe->SetValue(x); 
     /* lines of code */   
    } 

} 
+0

One nit : Vous pouvez utiliser un verrouillage automatique (voir CCritSecLock d'ATL par exemple) au lieu d'API de verrouillage et de libération explicites - il est plus difficile de se tromper. –

2

Si vous souhaitez implémenter la mise à jour thread-safe d'un entier, mieux vaut utiliser les fonctions InterlockedIncrement et InterlockedDecrement ou InterlockedExchangeAdd. Voir http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx.

Si vous avez besoin d'utiliser EnterCriticalSection et LeaveCriticalSection vous trouverez un exemple dans http://msdn.microsoft.com/en-us/library/ms686908(v=VS.85).aspx, mais je vous recommande d'utiliser EnterCriticalSection à l'intérieur du bloc et __tryLeaveCriticalSection à l'intérieur de la __finally partie de ce bloc.

+1

S'il vous plaît noter que les fonctions enclenchées sont SERIEUSEMENT difficiles à aller droit. Si tout ce que vous faites est d'incrémenter ou de décrémenter une variable, ils sont assez sûrs, mais il est étonnamment difficile de les utiliser correctement. En toute sincérité, je ne connais qu'une douzaine de personnes à MSFT à qui je ferais confiance pour écrire du code sans verrou (et je n'en fais pas partie). Vous êtes plus sûr lorsque vous entrez et sortez de la section critique. Si vous commencez à voir une utilisation excessive du CPU en raison des changements de contexte, initialisez le critsec avec un nombre de tours et cela devrait aider. –

+0

@Larry. Désolé mais je ne comprends pas ce qui est si complexe dans l'utilisation de fonctions interverrouillées. Ils sont extrêmement faciles à comprendre et offrent les meilleures performances dans toutes les architectures de processeurs. – Oleg

+1

Oleg: Le meilleur exemple que je connaisse est le "modèle de verrouillage à double vérification". Sur la surface, le DCLP est sûr, mais comme ceci: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html article explique, c'est en fait un modèle cassé. Herb Sutter a une grande colonne sur la concurrence référencée ici: http://herbsutter.com/2008/08/05/effective-concurrency-lock-free-code-a-false-sense-of-security/ –

Questions connexes