POSIX Threads/Synchronizacja między wątkami/Bariery
Wstęp
edytujBariera jest mechanizmem synchronizacji grupy wątków. Wątki po dojściu bo bariery są wstrzymywane do czasu, aż ostatni jej nie osiągnie - wówczas wszystkie są kontynuowane. Z barierą związana jest liczba większa od zera określająca ile wątków wchodzi w skład grupy.
Gdy bariera jest osiągana przez wszystkie wątki, jej stan (licznik) jest automatycznie inicjowany, na taką wartość, jaką ustawiło ostatnie wywołanie pthread_barrier_init.
Inicjalizacja bariery
edytujInicjalizację bariery wykonuje funkcja pthread_barrier_init, usuwa zaś funkcja pthread_barrier_destroy. Bariera może mieć dodatkowe atrybut.
Typy
edytuj- pthread_barrier_t
- bariera
- pthread_barrierattr_t
- atrybuty bariery
Funkcje
edytuj- int pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t* attr, unsigned int count) (doc)
- inicjalizacja bariery, count jest liczbą wątków w grupie, attr opcjonalne atrybuty
- int pthread_barrier_destroy(pthread_barrier_t *barrier) (doc)
- usunięcie bariery
Atrybuty bariery
edytujGdy biblioteka implementuje opcję TSH, wówczas można ustalić, czy bariery mogą być współdzielone między procesami - domyślnie nie.
Funkcje
edytuj- int pthread_barrierattr_init(pthread_barrierattr_t *attr) (doc)
- inicjacja atrybutów bariery
- int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) (doc)
- usunięcie atrybutów
- int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) (doc)
- ustawienie flagi współdzielenia z innymi procesami; pshared ma wartość PTHREAD_PROCESS_SHARED lub PTHREAD_PROCESS_PRIVATE (domyślnie)
- int pthread_barrierattr_getpshared(pthread_barrierattr_t *attr, int *pshared) (doc)
- odczytanie flagi
Bariera
edytujWywołanie funkcji pthread_barrier_wait jest traktowane jako dojście do bariery - powoduje zwiększenie licznika związanego z barierą.
Gdy bariera zostanie osiągnięta przez wszystkie wątki, funkcja w jednym wątku (standard nie określa w którym) zwraca specjalną wartość PTHREAD_BARRIER_SERIAL_THREAD, pozostałe wartość 0.
Funkcje
edytuj- int pthread_barrier_wait(pthread_barrier_t *barrier) (doc)
Przykład
edytujW programie bariera służy do wstrzymania programu, do czasu aż wszystkie utworzone wątki skończą działanie.
#define _POSIX_C_SOURCE 200809L
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define test_errno(msg) do{if (errno) {perror(msg); exit(EXIT_FAILURE);}} while(0)
pthread_barrier_t bariera;
void* watek(void* numer) {
int s, status;
s = rand() % 4 + 1; // oczekiwanie 1-4 s
printf("\twątek #%d rozpoczęty, zostanie wstrzymany na %d sekund\n", (int)numer, s);
sleep(s);
printf("\twątek #%d osiągnął barierę\n", (int)numer);
status = pthread_barrier_wait(&bariera);
switch (status) {
case 0: // ok
break;
case PTHREAD_BARRIER_SERIAL_THREAD:
printf(
"\twszystkie wątki osiągnęły barierę "
"(PTHREAD_BARRIER_SERIAL_THREAD w wąteku #%d)\n",
(int)numer
);
break;
default:
fprintf(stderr, "pthread_barrier_wait: %s\n", strerror(status));
break;
}
return NULL;
}
//------------------------------------------------------------------------
#define N 10 /* liczba wątków */
int main() {
int i;
pthread_t id[N];
srand(time(NULL));
printf("zostanie uruchomionych %d wątków\n", N);
/* inicjalizacja bariery - N wątków */
errno = pthread_barrier_init(&bariera, NULL, N);
test_errno("pthread_barrier_init");
/* utworzenie N wątków */
for (i=0; i < N; i++) {
errno = pthread_create(&id[i], NULL, watek, (void*)i);
test_errno("pthread_create");
}
/* oczekiwaie na dojście do bariery wszystkich wątków */
for (i=0; i < N; i++) {
errno = pthread_join(id[i], NULL);
test_errno("pthread_join");
}
/* zwolnienie bariery */
errno = pthread_barrier_destroy(&bariera);
test_errno("pthread_barrier_destroy");
return EXIT_SUCCESS;
}
//------------------------------------------------------------------------
Przykładowe wyjście:
zostanie uruchomionych 10 wątków wątek #0 rozpoczęty, zostanie wstrzymany na 0 sekund wątek #0 osiągnął barierę wątek #1 rozpoczęty, zostanie wstrzymany na 0 sekund wątek #1 osiągnął barierę wątek #2 rozpoczęty, zostanie wstrzymany na 0 sekund wątek #2 osiągnął barierę wątek #3 rozpoczęty, zostanie wstrzymany na 0 sekund wątek #3 osiągnął barierę wątek #4 rozpoczęty, zostanie wstrzymany na 4 sekund wątek #5 rozpoczęty, zostanie wstrzymany na 4 sekund wątek #6 rozpoczęty, zostanie wstrzymany na 3 sekund wątek #7 rozpoczęty, zostanie wstrzymany na 4 sekund wątek #8 rozpoczęty, zostanie wstrzymany na 4 sekund wątek #9 rozpoczęty, zostanie wstrzymany na 4 sekund wątek główny osiągnął barierę wątek #6 osiągnął barierę wątek #4 osiągnął barierę wątek #5 osiągnął barierę wątek #7 osiągnął barierę wątek #8 osiągnął barierę wszystkie wątki osiągnęły barierę (wątek #9)