POSIX Threads/Przykładowe programy/Program 16

Z Wikibooks, biblioteki wolnych podręczników.
/*
 *	Przykładowy program dla kursu "POSIX Threads" z wikibooks.pl
 *
 *	Temat: blokady zapis/odczy (rwlock)
 *
 *	Autor: Wojciech Muła
 *	Ostatnia zmiana: 2010-03-xx
 */
#define _POSIX_C_SOURCE	200809L
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>

void ms_sleep(const unsigned ms);
#define test_errno(msg) do{if (errno) {perror(msg); exit(EXIT_FAILURE);}} while(0)


pthread_rwlock_t	blokada;
int			wartosc;	// obiekt chroniony blokadą

/* wątek zmienia wartość */
void* pisarz(void* numer) {
	while (1) {
		printf(" pisarz #%d czeka na dostęp\n", (int)numer);
		errno = pthread_rwlock_wrlock(&blokada);
		test_errno("pthread_rwlock_wrlock");
		printf(" pisarz #%d ustawia nową wartość\n", (int)numer);

		ms_sleep(113);

		printf(" pisarz #%d zwalnia blokadę\n", (int)numer);
		errno = pthread_rwlock_unlock(&blokada);
		test_errno("pthread_rwlock_unlock");

		ms_sleep(317);

	}

	return NULL;
}
//------------------------------------------------------------------------

/* wątek tylko odczytuje wartość */
void* czytelnik(void* numer) {
	int errno;
	while (1) {
		printf("  czytelnik #%d czeka na dostęp\n", (int)numer);
		errno = pthread_rwlock_rdlock(&blokada);
		test_errno("pthread_rwlock_rdlock");
		printf("  czytelnik #%d odczytuje wartość\n", (int)numer);

		ms_sleep(13);

		printf("  czytelnik #%d zwalnia blokadę\n", (int)numer);
		errno = pthread_rwlock_unlock(&blokada);
		test_errno("pthread_rwlock_unlock");

		ms_sleep(13);

	}
	return NULL;
}
//------------------------------------------------------------------------

#define N 5 /* liczba wątków */
#define K 2

int main() {
	pthread_t id;
	int i;

	pthread_rwlock_init(&blokada, NULL);

	/* utworzenie K wątków piszących */
	for (i=0; i < K; i++) {
		errno = pthread_create(&id, NULL, pisarz, (void*)i);
		test_errno("pthread_create");
	}

	/* utworzenie N wątków czytających */
	for (i=0; i < N; i++) {
		errno = pthread_create(&id, NULL, czytelnik, (void*)i);
		test_errno("pthread_create");
	}

	/* kilka sekund na pracę wątków i koniec */
	ms_sleep(1500);

	return EXIT_SUCCESS;
}
//------------------------------------------------------------------------

void ms_sleep(const unsigned ms) {
	struct timespec req;
	req.tv_sec  = (ms / 1000);
	req.tv_nsec = (ms % 1000 * 1000000);
	nanosleep(&req, NULL);
}
//------------------------------------------------------------------------