Oct 15 2009

Watki w C

Po tym jak napisalismy i uruchomilismy nasz programik helloworld, mozemy teraz przejsc do bardziej ciekawych rzeczy. Na rozgrzewke proponuje pare watkow. Naszymi bohaterami beda, zbieracze zbierajacy ziarno z pola i znoszacy je do spichlerza.

Czym jest watek? Nie wiem jak w innych systemach, ale w unixach jest to proces, wykonywany w watku glownym, ktory jest procesem ;) . Dobrze, jak juz wiemy co to jest watek to przejdziemy dalej.

Tworzymy plik programu

czlowiek@maszyna:~$ nano seeds.c

Dolaczamy pliki naglowkowe

#include <stdio.h>
#include <string.h>
#include <pthread.h>

Tworzymy globalne przechowywacze oraz strukture wlasciwosci zbieracza

int grain; // ziarno na polu
int granary; // ziarno w spichlerzu
 
// struktura wlasciwosci zbieracza
struct collector
{
	char name[32]; // nazwa zbieracza
	int seeds; // ilosc zebranych ziaren
	int performance; // wydajnosc
};

I funkcje watku zbieracza – bedzie wywolywana podczas kazdego utworzenia

void* collect_seeds (void* collector_data)
{
	// pobranie danych zbieracza
	struct collector *data;
	data = (struct collector *) collector_data;
 
	// zebranie ziarna
	int collected;
	collected = data->performance;
	if (collected <= grain) {
		grain = grain - collected;
	} else {
		collected = grain;
		grain = 0;
	}
 
	// aktualizacja danych zbieracza
	data->seeds = data->seeds + collected;
	printf ("%s zebral %i\n", data->name, collected);
 
	// zwrocenie ilosci zebranych ziaren
	return (void*) collected;
}

A teraz watek glowny

int main (int argc, char *argv[])
{
	// ustalenie ilosci ziarna
	if (argc == 2 && atoi(argv[1]) > 0) {
		grain = atoi(argv[1]);
	}
	if (grain == 0)
		grain = 1000;
	granary = 1; // nie wymietli wszystkiego ; )
 
	// mieszadlo liczb losowych
	srand (time (0));
 
	// ustalanie danych zbieraczy
	struct collector collector1;
	strncpy (collector1.name, "Dziwigor", sizeof (collector1.name) - 1);
	collector1.seeds = 0;
	collector1.performance = rand() % 10 + 1; // losowanie wydajnosci
 
	struct collector collector2;
	strncpy (collector2.name, "Niesiebud", sizeof (collector2.name) - 1);
	collector2.seeds = 0;
	collector2.performance = rand() % 10 + 1;
 
	printf ("Ziarno na polu: %i ziaren\n", grain);
	printf ("Ziarno w spichlerzu: %i ziaren\n", granary);
	printf ("Zaczely sie zniwa\n\n");
 
	int collected_seeds;
 
	// wskazniki do watkow zbieraczy
	pthread_t thread1;
	pthread_t thread2;
 
	// petelka dopoki nie zostanie zebrane cale ziarno
	while (grain > 0) {

Do tej pory luzik wszystko wiadomo, tworzenie i ustalanie wartosci zmiennych, no i teraz dochodzimy do najwazniejszego elementu programiku – wyzwalanie watkow

Utworzenie watku

		// utworzenie watku Dziwigora
		pthread_create (&thread1, NULL, collect_seeds, (void*)&collector1);

Pobranie danych z watku

		// pobranie zebranych ziaren
		pthread_join (thread1, (void*) &collected_seeds);

“Przesypanie” ziarna do spichlerza, i tak w kolko, dopoki ludki nie zbiora wszystkiego

		// aktualizacja spichlerza
		granary = granary + collected_seeds;
 
		pthread_create (&thread2, NULL, (void*) collect_seeds, (void*)&collector2);
		pthread_join (thread1, (void*) &collected_seeds);
		granary = granary + collected_seeds;
 
		printf ("Pozostalo: %i ziaren\n", grain);
	}
 
	printf ("\nZniwa zakonczone\n");
	printf ("%s zebral %i\n", collector1.name, collector1.seeds);
	printf ("%s zebral %i\n", collector2.name, collector2.seeds);
 
	printf ("Ziarno na polu: %i ziaren\n", grain);
	printf ("Ziarno w spichlerzu: %i ziaren\n", granary);
}

Jezeli skonczylismy pisac kod, to kompilujemy programik

czlowiek@maszyna:~$ gcc -o seeds seeds.c -pthread

za pomoca parametru -pthread informujemy kompilator aby dolaczyl obpowiednie biblioteki, jak tego nie zrobimy to sofcik oczywiscie nie skompiluje sie.

Uruchamiamy programik

czlowiek@maszyna:~$ ./seeds 100
Ziarno na polu: 100 ziaren
Ziarno w spichlerzu: 1 ziaren
Zaczely sie zniwa

Dziwigor zebral 5
Niesiebud zebral 6
Pozostalo: 89 ziaren
Dziwigor zebral 5
Niesiebud zebral 6
Pozostalo: 78 ziaren
...
Dziwigor zebral 5
Niesiebud zebral 6
Pozostalo: 1 ziaren
Dziwigor zebral 1
Niesiebud zebral 0
Pozostalo: 0 ziaren

Zniwa zakonczone
Dziwigor zebral 46
Niesiebud zebral 54
Ziarno na polu: 0 ziaren
Ziarno w spichlerzu: 101 ziaren

Gdy widzimy cos podobnego to odnieslismy kolejny sukces ;) .

Tutaj wersja dla niecierpliwych:
Pobierz zrodlo i/lub binarke


Zostaw odpowiedz