Thread-Barrier in WinAPI?



  • Jochen Kalmbach schrieb:

    Du meinst, wenn sowas gemacht wird?

    int ThreadProc()
    {
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
       pthread_barrier_wait(..);
    }
    

    Und der Thread eben x-Mal gestartet wird?

    Zum Beispiel, ja.

    Das sollte sich mit Events relativ einfach nachbauen lassen... einfacher geht es vermutlich noch, wenn man vor dem return noch ein Semaphor macht, wo wieder alle Durch müssen... dann kann man vorher den Event wieder resetten...

    Sollte, müsste, könnte. Zeig her wenn du was hast! 🙂

    (Muss nicht super-performant sein, mir reicht völlig wenn es einfach ist, und korrekt. Wie gesagt: ich hab bis jetzt noch keine Variante gefunden, die einfacher wäre, als sich eine Condition-Variable nachzubauen. Und natürlich gilt es nicht die neuen Vista+ Funktionen (SleepConditionVariableCS etc.) zu verwenden.)



  • Folgendes sollte Problemlos funktionieren:

    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    #include <process.h>
    #include <errno.h>
    
    #define PTHREAD_BARRIER_SERIAL_THREAD 1
    
    typedef struct 
    { 
      HANDLE hEvt; 
      HANDLE hEvtSync; 
      volatile LONG lCount; 
      LONG lOrgCount;
    } pthread_barrier_t;
    
    int pthread_barrier_init(pthread_barrier_t* barrier, unsigned count) 
    { 
      barrier->hEvt = CreateEvent(NULL, FALSE, FALSE, NULL); 
      barrier->hEvtSync = CreateEvent(NULL, TRUE, FALSE, NULL); 
      barrier->lCount = count; 
      barrier->lOrgCount = count; 
      return 0;
    } 
    
    int pthread_barrier_wait(pthread_barrier_t *barrier) 
    { 
      if (barrier == NULL) 
        return EINVAL; 
      LONG lLast = InterlockedDecrement(&barrier->lCount); 
      if (lLast == 0) 
      {
        // Stelle sicher, dass nacher alle wieder anhalten...
        ResetEvent(barrier->hEvtSync);
        SetEvent(barrier->hEvt); 
      }
    
      // Hier kommt immer nur *einer* raus...
      WaitForSingleObject(barrier->hEvt, INFINITE); 
    
      // So, gehe jetzt wieder anders rum durch, bis ich bei lOrgCount bin
      LONG lLastNext = InterlockedIncrement(&barrier->lCount); 
      if (lLastNext == barrier->lOrgCount)
      {
        // jetzt sind alle wieder drausen, also bin ich wieder synchron...
        SetEvent(barrier->hEvtSync);
      }
      else
      {
        // Hab den Zähler noch nicht erreicht, lasse somit den nächsten raus...
        SetEvent(barrier->hEvt); 
        // ... und warte bis alle drausen sind
        WaitForSingleObject(barrier->hEvtSync, INFINITE); 
      }
    
      if (lLast == 0)
      {
        return PTHREAD_BARRIER_SERIAL_THREAD; 
      }
      return 0; 
    } 
    
    int pthread_barrier_destroy(pthread_barrier_t *barrier) 
    { 
      CloseHandle(barrier->hEvt); 
      CloseHandle(barrier->hEvtSync); 
      return 0;
    }
    
    void t(void* p)
    {
      pthread_barrier_t *b = (pthread_barrier_t*) p;
    
      printf("1");
      pthread_barrier_wait(b);
      printf("2");
      pthread_barrier_wait(b);
      printf("3");
      pthread_barrier_wait(b);
      printf("4");
      pthread_barrier_wait(b);
      printf("5");
      pthread_barrier_wait(b);
      printf("6");
      pthread_barrier_wait(b);
    }
    
    int _tmain()
    {
      int cnt = 5;
      pthread_barrier_t b;
      pthread_barrier_init(&b, cnt);
    
      for(int i=0; i<cnt; i++)
      {
        _beginthread(t, 0, &b);
      }
      while(1) Sleep(100);
    
      pthread_barrier_destroy(&b);
    }
    

  • Mod

    Also bei Deinem Code gibt es auch ein Problem, wenn esmehr als n Threads gibt.
    Dann gibt es bei Dir einen Underflow.
    Der n+1teThread wird auch angehalten, wird aber sofort wieder von n-then Thread losgelassen.

    Oder liege ich da falsch?

    Das gleiche Problem, wie bei meiner Semaphore Lösung.
    Das Problem ist, dass eigentlich nicht definiert ist was passiert wen es mehr Threads gibt.



  • Martin Richter schrieb:

    Also bei Deinem Code gibt es auch ein Problem, wenn esmehr als n Threads gibt.

    Also, durch Fehlbedienung geht natürlich alles schief... wenn natürlich mehr Threads das Ding aufrufen als beim Erzeugen angegeben wurde, dann besteht eh ein Programmierfehler... oder hab ich da jetzt was in der Docu zu dem barrier übersehen...



  • Pfuh.

    Keine Ahnung ob die PTHREADS API erlaubt dass mehr als N Threads da reinfahren.
    Allerdings würde ich eine Implementierung immer so auslegen, dass es trotzdem korrekt funktioniert.



  • hustbaer schrieb:

    Pfuh.

    Keine Ahnung ob die PTHREADS API erlaubt dass mehr als N Threads da reinfahren.
    Allerdings würde ich eine Implementierung immer so auslegen, dass es trotzdem korrekt funktioniert.

    Wie soll denn das gehen?
    Es ist das GIGO Prinzip! (Garbage-In-Garbage-Out).

    PS: Mir fehlt immer noch Dein Kommentar, ob das jetzt Deinen Wünschen entspricht...


  • Mod

    Jochen Kalmbach schrieb:

    Es ist das GIGO Prinzip! (Garbage-In-Garbage-Out).

    Jein!

    Wenn die Regel lautet belieg viele Threads, dann würde folgendes passieren
    Thread 1 kommt an wartet auf Thread n, wird 0 zurückgeben
    Thread 2 kommt an wartet auf Thread n, wird 0 zurückgeben
    ...
    Thread n-1 kommt an wartet auf Thread n wird 0 zurückgeben

    Die nächsten 3 Anrufe sind zeitgleich:
    Thread n kommt an und wir den Magic zurückgeben
    Thread n+1 kommt an und wartet nun das zum 2n-ten Male die Funktion gerufen wird.
    Thread n+2 kommt an und wartet nun das zum 2
    n-ten Male die Funktion gerufen wird.

    Das wäre kein Garbage. Es kommt auf die Definition an.



  • So lange es sich gleich verhält wie unter pthreads, hab ich damit keine Probleme 😉



  • Hallo,

    immerhin gibt es das hier (nur als Ergänzung):

    http://msdn.microsoft.com/en-us/library/b8t6afft.aspx

    MfG,

    Probe-Nutzer



  • Jochen Kalmbach schrieb:

    hustbaer schrieb:

    Pfuh.

    Keine Ahnung ob die PTHREADS API erlaubt dass mehr als N Threads da reinfahren.
    Allerdings würde ich eine Implementierung immer so auslegen, dass es trotzdem korrekt funktioniert.

    Wie soll denn das gehen?
    Es ist das GIGO Prinzip! (Garbage-In-Garbage-Out).

    PS: Mir fehlt immer noch Dein Kommentar, ob das jetzt Deinen Wünschen entspricht...

    Er.
    Sorry für die späte Antwort.

    Was heisst meinen Wünschen 🙂
    Ich brauch sowas nicht, ich verwende selbst die Boost.Thread wenn ich was derartiges brauche.

    Wenn du meinst ob ich es anerkenne als "einfacher als wenn man sich eine eigene Condition-Variablen Implementierung strickt"... nö. Es ist wesentlich weniger Code, aber dafür (für mich) schwerer zu verstehen. (Und natürlich wesentlich langsamer, was ich aber explizit als Kriterium ausgenommen hatte)


Anmelden zum Antworten