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


Oct 13 2009

Hello world w C/C++

Wstep do programowania C/C++ w Linuxie zaczniemy standardowo od programiku helloworld.

Przygotowujemy srodowisko

czlowiek@maszyna:~$ sudo apt-get install build-essential

i to juz wystarczy aby napisac prosty programik w C.

Generujemy kod programiku

czlowiek@maszyna:~$ nano helloworld.c
#include <stdio.h>
 
int main (int argc, char *argv[])
{
	printf ("Hello World!\n");
	return 0;
}

Kompilujemy programik korzystajac ze standardowego gcc (gcc [opcje] plik)

czlowiek@maszyna:~$ gcc -o helloworld helloworld.c

Uruchamiamy programik

czlowiek@maszyna:~$ ./helloworld
Hello World!

Niama. To teraz C++

Generujemy kodzik

czlowiek@maszyna:~$ nano helloworld.cpp
#include <iostream>
 
int main (int argc, char *argv[])
{
	std::cout << "Hello World!" << std::endl;
	return 0;
}

Kompilujemy korzystajac tym razem z g++ (g++ [opcje] plik)

czlowiek@maszyna:~$ g++ -o helloworld_c++ helloworld.cpp

Uruchamiamy programik

czlowiek@maszyna:~$ ./helloworld_c++
Hello World!

cool. To pobawmy sie.

Tworzymy plik viewparams.c

czlowiek@maszyna:~$ nano viewparams.c

i wstawiamy to

#include <stdio.h>
 
int main (int argc, char *argv[])
{
	printf ("argc = %d\n", argc);
	int i;
	for (i = 0; argv[i]; i++) {
		printf("argv[%d]", i);
		printf(" = %s\n", argv[i]);
	}
	return 0;
}

Kompilujemy i uruchamiamy programik z parametrami

czlowiek@maszyna:~$ gcc -o viewparams viewparams.c
czlowiek@maszyna:~$ ./viewparams parametr1 parametr2 parametr3
argc = 4
argv[0] = ./viewparams
argv[1] = parametr1
argv[2] = parametr2
argv[3] = parametr3

Teraz programik plus

czlowiek@maszyna:~$ nano plus.c
#include <stdio.h>
 
int main (int argc, char *argv[])
{
	if (argc < 3) {
		printf ("Niepoprawna liczba argumentow :/\n");
		printf ("Przyklad uzycia: plus 50 25\n");
		return 1;
	}
	int sum, i;
	sum = 0;
	for (i = 0; argv[i]; i++) {
		sum += atoi(argv[i]);
	}
	printf ("%d\n", sum);
	return 0;
}

Kompilujemy i uruchamiamy

czlowiek@maszyna:~$ gcc -o plus plus.c
czlowiek@maszyna:~$ ./plus 50 25
75
czlowiek@maszyna:~$ ./plus 1 2 3 4 5 6 7 8 9 0
45

plus-minus? ;)