POSIX Threads/Przykładowe programy/Program 10

/*
 *	Przykładowy program dla kursu "POSIX Threads" z wikibooks.pl
 *
 *	Temat: prywatne dane wątków
 *
 *	Autor: Wojciech Muła
 *	Ostatnia zmiana: 2010-03-xx
 */
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

#define test_errno(info) do {if (errno) {perror(info); exit(EXIT_FAILURE);}} while(0)

pthread_key_t	klucz;

/* funkcja wypsuje wiersz, poprzedząjąc go prefiksem przypisanym do wątku */
void wyswietl(const char* napis) {
	char* prefiks = (char*)pthread_getspecific(klucz);
	if (prefiks == NULL)
		/* należy zabezpieczyć się przed sytuacją, gdy wywołujący
		   wątek nie przyporządkował nic do klucza */
		puts(napis);
	else
		printf("%s: %s\n", prefiks, napis);
}
//---------------------------------------------------------------------------

/* destruktor klucza */
void destruktor(void* napis) {
	printf("wywołano destruktor, adres pamięci do zwoleniania: %p ('%s')\n",
		napis,
		(char*)napis
	);
	free(napis);
}
//---------------------------------------------------------------------------

void* watek(void* napis) {
	/* ustawienie prefiksu w lokalnych danych wątku */
	int status = pthread_setspecific(klucz, napis);
	if (status)
		fprintf(stderr, "pthread_setspecific: %s\n", strerror(status));
	else
		printf("adres napisu: %p ('%s')\n", napis, (char*)napis);

	wyswietl("Witaj w równoległym świecie!");
	sleep(1);
	wyswietl("Wątek wykonuje pracę");
	sleep(1);
	wyswietl("Wątek zakończony");
	return NULL;
}
//---------------------------------------------------------------------------

char* strdup(const char*);

#define N 3

int main() {
	pthread_t id[N];
	int i;
	char* prefiks[3] = {"***", "!!!", "###"}; // prefiksy dla komunikatów z wątków

	/* utworzenie klucza */
	errno = pthread_key_create(&klucz, destruktor);
	test_errno("pthread_key_create");

	/* utworzenie wątków */
	for (i=0; i < N; i++) {
		errno = pthread_create(&id[i], NULL, watek, (void*)strdup(prefiks[i % 3]));
		test_errno("pthread_create");
	}

	/* oczekiwanie na ich zakończenie */
	for (i=0; i < N; i++)
		pthread_join(id[i], NULL);

	/* usunięcie klucza */
	errno = pthread_key_delete(klucz);
	test_errno("pthread_key_delete");

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

char* strdup(const char* s) {
	char *d = NULL;
	if (s) {
		d = (char*)malloc(strlen(s)+1);
		if (d)
			strcpy(d, s);
	}
	return d;
}
//---------------------------------------------------------------------------