POSIX Threads/Przykładowe programy/Program 7

/*
 *	Przykładowy program dla kursu "POSIX Threads" z wikibooks.pl
 *
 *	Temat:	przerywanie wątków - program tworzy 3 wątki z różnymi
 *		ustawieniami dotyczącymi przerywania:
 *		1) dopuszcza przerwanie asynchroniczne
 *		2) dopuszcza przerwanie opóźnione
 *		3) przez pewien czas w ogóle blokuje przerwania
 *
 *	Autor: Wojciech Muła
 *	Ostatnia zmiana: 2010-03-xx
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>	// pause w watek3
#include <errno.h>

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

void zakonczenie(void* numer) {
	printf("funkcja finalizująca dla wątku #%d\n", (int)numer);
}
//------------------------------------------------------------------------

void* watek1(void* numer) {
	int i, n;

	pthread_cleanup_push(zakonczenie, numer);

	errno = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	test_errno("pthread_setcancelstate");

	errno = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
	test_errno("pthread_setcanceltype");

	printf("\turuchomiono wątek #%d (przerwanie asynchroniczne)\n", (int)numer);
	while (1) {
		n = 1000000;
		for (i=0; i < n; i++)
			/**/;
	}

	pthread_cleanup_pop(1);
	return NULL;
}
//------------------------------------------------------------------------

void* watek2(void* numer) {
	int i, n;
	pthread_cleanup_push(zakonczenie, numer);

	errno = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	test_errno("pthread_setcancelstate");

	errno = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
	test_errno("pthread_setcanceltype");

	printf("\turuchomiono wątek #%d (przerwanie opóźnione)\n", (int)numer);
	while (1) {
		pthread_testcancel();	// punkt przerwania
		n = 1000000;
		for (i=0; i < n; i++)
			/**/;
	}

	pthread_cleanup_pop(1);
	return NULL;
}
//------------------------------------------------------------------------

void* watek3(void* numer) {
	pthread_cleanup_push(zakonczenie, numer);
	errno = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	test_errno("pthread_setcancelstate");

	printf("\turuchomiono wątek #%d (przez 2 sekundy nie można przerwać)\n", (int)numer);

	sleep(2);

	printf("\twątek #%d można już przerwać\n", (int)numer);
	errno = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	test_errno("pthread_setcancelstate");
	pause();

	pthread_cleanup_pop(1);
	return NULL;
}
//------------------------------------------------------------------------

void przerwanie(pthread_t id, const char* napis) {
	printf("%s: wysyłanie sygnału przerwania do wątku\n", napis);
	errno = pthread_cancel(id);
	test_errno("pthread_cancel");

	printf("%s: wysłano, oczekiwanie na zakończenie\n", napis);
	errno = pthread_join(id, NULL);
	test_errno("pthread_join");

	printf("%s: wątek zakończony\n", napis);
}
//------------------------------------------------------------------------

int main() {
	pthread_t id[3];

	/* utworzenie wątków */
	errno = pthread_create(&id[0], NULL, watek1, (void*)(0));
	test_errno("pthread_create (1)");

	errno = pthread_create(&id[1], NULL, watek2, (void*)(1));
	test_errno("pthread_create (2)");

	errno = pthread_create(&id[2], NULL, watek3, (void*)(2));
	test_errno("pthread_create (3)");

	/* przerywanie kolejnych wątków */
	przerwanie(id[0], "#0");
	przerwanie(id[1], "#1");
	przerwanie(id[2], "#2");

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