UŻYCIE I ZARZĄDZANIE WĄTKAMI

Podobne dokumenty
UŻYCIE I ZARZĄDZANIE WĄTKAMI

Procesy i wątki. Krzysztof Banaś Obliczenia równoległe 1

Łącza nienazwane(potoki) Łącza nienazwane mogą być używane tylko pomiędzy procesami ze sobą powiązanymi.

Temat zajęć: Tworzenie i obsługa wątków.

Procesy. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 9 października 2011

Poniższe funkcje opisane są w 2 i 3 części pomocy systemowej.

w odróżnieniu od procesów współdzielą przestrzeń adresową mogą komunikować się za pomocą zmiennych globalnych

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

Wykład 3. Procesy i wątki. Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

Funkcja (podprogram) void

procesy odrębne dzielone

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Laboratorium Systemów Operacyjnych. Ćwiczenie 4. Operacje na plikach

Programowanie Współbieżne

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Wstęp do Programowania, laboratorium 02

Systemy Operacyjne 1 Laboratorium 2 Procesy i sygnały w Linuksie (jeden tydzień) dr inż. Arkadiusz Chrobot

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Temat zajęć: Obsługa procesów w systemie.

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Model procesu w systemie Linux. Tomasz Borzyszkowski

Tablice, funkcje - wprowadzenie

Tworzenie programów równoległych cd. Krzysztof Banaś Obliczenia równoległe 1

Wstęp do programowania

Sygnały. 7. Sygnały (2005/2006)

Metody Metody, parametry, zwracanie wartości

3 Przygotował: mgr inż. Maciej Lasota

1 Zapoznanie się ze środowiskiem Xenomai.

Wykład 1

Programowanie I. O czym będziemy mówili. Plan wykładu nieco dokładniej. Plan wykładu z lotu ptaka. Podstawy programowania w językach. Uwaga!

1. Uruchom poniższy program tworzący pojedynczy wątek:

Instrukcja do laboratorium Systemów Operacyjnych. (semestr drugi)

1 Podstawy c++ w pigułce.

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Programowanie I C / C++ laboratorium 02 Składnia pętli, typy zmiennych, operatory

4. Procesy pojęcia podstawowe

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

4.2 Sposób korzystania z l acza

Język C zajęcia nr 11. Funkcje

W języku C dostępne są trzy instrukcje, umożliwiające tworzenie pętli: for, while oraz do. for (w1;w2;w3) instrukcja

Programowanie I C / C++ laboratorium 03 arytmetyka, operatory

Programowanie Proceduralne

Obsługa plików Procesy

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Część 4 życie programu

4. Procesy pojęcia podstawowe

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

1. Procesy i współbieżność

wykład III uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - zarządzanie pamięcią, struktury,

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Podstawy programowania skrót z wykładów:

Pobieranie argumentów wiersza polecenia

2 Przygotował: mgr inż. Maciej Lasota

Wykład VI. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

Pliki w C/C++ Przykłady na podstawie materiałów dr T. Jeleniewskiego

2. Zarządzanie procesami

Procesy. S. Samolej: Procesy

Podstawy programowania. Wykład: 4. Instrukcje sterujące, operatory. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Wskaźniki w C. Anna Gogolińska

3. Identyfikacja. SKŁADNIA #include <sys/socket.h> int getpeername(int socket, struct sockaddr *addr, int *addrlen);

Dzisiejszy wykład. Klasa string. wersja prosta wersja ze zliczaniem odwołań. Wyjątki Specyfikator volatile Semafory

Instrukcja wyboru, pętle. 2 wykład. Podstawy programowania - Paskal

Wykład 15. Literatura. Kompilatory. Elementarne różnice. Preprocesor. Słowa kluczowe

Zarządzanie Procesami

PROGRAMOWANIE w C prolog

Plan wykładu. Obliczenia równoległe w zagadnieniach inżynierskich. Wykład 1 p. Wzajemne wykluczanie. Procesy współbieżne

Liczby pseudolosowe. #include <stdio.h> #include <stdlib.h> int main() { printf("%d\n", RAND_MAX); return 0; }

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Programowanie I C / C++ laboratorium 01 Organizacja zajęć

Wielozadaniowość w systemie Microsoft Windows

WYKŁAD 8. Funkcje i algorytmy rekurencyjne Proste przykłady. Programy: c3_1.c..., c3_6.c. Tomasz Zieliński

1 Podstawy c++ w pigułce.

Aplikacja Sieciowa wątki po stronie klienta

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk

Wskaźniki. Informatyka

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Co nie powinno być umieszczane w plikach nagłówkowych:

Programowanie równoległe i rozproszone. Monitory i zmienne warunku. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Podstawy programowania w języku C++

Wskaźniki. Programowanie Proceduralne 1

Systemy Operacyjne 2: Wątki pthreads. dr inż. Arkadiusz Chrobot

Podstawy programowania. Wykład: 5. Instrukcje sterujące c.d. Stałe, Typy zmiennych c.d. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Uzupełnienie dot. przekazywania argumentów

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Ćwiczenie nr 3. Temat: Definicje i wykorzystanie funkcji, parametry funkcji

Systemy Operacyjne - Operacje na plikach

Język C : programowanie dla początkujących : przewodnik dla adeptów programowania / Greg Perry, Dean Miller. Gliwice, cop

5 Przygotował: mgr inż. Maciej Lasota

Zajęcia nr 1 Podstawy programowania. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

/* dołączenie pliku nagłówkowego zawierającego deklaracje symboli dla wykorzystywanego mikrokontrolera */ #include <aduc834.h>

4. Procesy pojęcia podstawowe

Łącza nienazwane(potoki)

Transkrypt:

Proces jako pewna instancja programu, w trakcie wykonania, ze swej natury w każdym systemie operacyjnym wyróżniają: prawa własności zasobu a jednym z fundamentalnych zadań systemu jest ochrona przed jednoczesnym dostępem; szeregowanie i wykonanie procesów odbywa się z poziomu systemu operacyjnego. W odróżnieniu od procesu, wątek stanowi podzbiór przestrzeni adresowej procesu, współdzielący jego stan i zasoby (również deskryptory plików) aczkolwiek nie dziedziczy stosu procesu (stack). Dzięki temu komunikacja między wątkowa nie wymaga użycia systemowych mechanizmów inter-process communication a przełączanie kontekstu (context switch) jest niewspółmiernie szybsze niż w przypadku procesu. Z racji wygody użycia istnieje wiele implementacji bibliotek obsługujących wielowątkowość. Dla systemów POSIX standardem jest POSIX 1003.1c standard (1995) pthreads, czyli POSIX THREADS Ponieważ jest uzupełnieniem API systemowego, wymagana jest jawna konsolidacja z libpthread.so (albo libpthread.a) gcc -Wall <source>.c -o <exec> -lpthread O wątkach LINUXowych więcej http://sunsite.unc.edu/pub/linux/docs/faqs/threads-faq/html/ 1

Podobnie jak każdemu procesowi w chwili jego tworzenia przypisywane jest unikalne pid_t id; tak też i wątkowi przypisywane jest pthread_t id; Wątek może pobrać swój własny identyfikator wywołaniem #include <pthread.h> pthrad_t pthread_self(void); Tworzenie nowego, wątku potomnego odbywa się wywołaniem funkcji pthread_create() SYNOPSIS #include <pthread.h> int pthread_create( pthread_t *tid,const pthread_attr_t *attr, void *(*thread)(void*),void *arg ); pthread_t *tid, identyfikator nowotworzonego wątku (jeżeli sukces) pthread_attr_t*attr,sposób dołączania,kolejkowania wątku (domyślnie NULL) thread(), funkcja wątku void *arg, argument dla funkcji startowej,, NULL jeżeli brak RETURN 0,jeżeli sukces 2

Zakończenie wątku może nastąpić z czterech przyczyn: zwrócenie sterowania z wątku (wywołanie return, exit(), _exit()); wywołanie z wątku nadrzędnego (macierzystego); z innego wątku wywołaniem #include <pthread.h> int pthread_cancel( pthread_t tid ); jawne wywołanie funkcji pthread_exit() z kodem powrotu code. #include <pthread.h> void pthread_exit( void *code ); Wykonajmy najpierw prosty przykład kiedy dwa wątki będą pisać na konsoli. Kod ciała wątku głównego przedstawiał się będzie następująco #include<stdio.h> #include<pthread.h> #define ENDLESS 1 int main( void ) pthread_t tid; pthread_create( &tid,null,&o,null ); while( ENDLESS ) putchar( 'x' ); return 0; 3

Funkcja wątku będzie miała prostą definicję void* o( void* unused ) (void)unused; while( ENDLESS ) putchar( 'o' ); return 0; Jeżeli zapiszemy kod źródłowy pod nazwą xox.c, to kompilację i konsolidację wykonujemy komendą $ gcc -Wall xox.c -o xox -lpthread a wykonanie, o ile powyższa akcja zakończyła się sukcesem $./xox xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooooooooooooooxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xoooooooooooooooooooooooooooooooooooooo^c Program ten, a ściślej wątki możemy zatrzymać wyłącznie wysyłając odpowiedni sygnał. Zwróćmy uwagę, że tak jak wspominano to już wcześniej, nie możemy czynić żadnych założeń a priori odnośnie relacji czasowych wykonujących się równolegle zadań. 4

Przygotujemy teraz program, którego proces utworzy tyle wątków ile podanych będzie w linii wywołania programu. Zaczynamy od deklaracji plików nagłówkowych #include <stdlib.h>... bo exit() i stałe symboliczne #include <stdio.h>... operacje wejścia-wyjścia #include <unistd.h>... pobranie PID procesu, przy pomocy getpid() #include <pthread.h>... wątki, oczywiście niezbędne Deklaracja nagłówkowa funkcji main() int main( int argc,char *argv[] ) pthread_t tid;... tu będzie zwracane TID przez pthread_create() int rc;... wartość zwracana przez pthread_create() long i,n;... zmienne sterujące pętli tworzącej wątki Deklaracja funkcji wątku. void* hello( void*);... i możemy przystępować do rzeczy 5

Sprawdzamy, czy aby wywołanie programu było poprawne if( argc>1 )... no można by właściwie arrc==2 Najpierw czytamy z linii wywołania ilość wątków, do zmiennej n sscanf( argv[1],"%ld",&n ); Przystępujemy do tworzenia zadanej ilość wątków for( i=0;i<n;i++ ) Informacja diagnostyczna printf( "PID[%ld] tworzy wątek,...#%ld...\n", (long)getpid(),(i+1)); Tworzymy nowy wątek (i+1) żaby pierwszy był 1 rc = pthread_create( &tid, NULL,hello,(void *)(i+1)); Drobna diagnostyka błędów if(rc)perror( "!.!.!...błąd pthread_create()...");exit(rc); else... na wypadek błędnego wywołania programu printf( "!.!.!... wywołanie powinno mieć postać: %s %s\n", argv[0],"<ilość_wątków>" ); Oczywiście proces można zakończyć i tak... pthread_exit( NULL );... wszakże jest wątkiem! 6

Pozostało jeszcze przygotować funkcję wątku hello(). void* hello( void *n ) Wyświetlamy informację diagnostyczną printf("pid[%ld]...jestem wątkiem #%ld! TID[%d]\n", (long)getpid(),(long)n,(int)pthread_self() ); i wątek kończy działanie pthread_exit( NULL );...właściwie to wywołanie jest zbędne Kompilacja i konsolidacja jeżeli kod źródłowy zapisano pod nazwą hello.c - oczywiście $ gcc -Wall helllo.c -o hello -lpthread Uruchomienie $./hello 4 PID[5874] tworzy wątek,... #1... PID[5874] tworzy wątek,... #2... PID[5874] tworzy wątek,... #3... PID[5874]...jestem wątkiem #1! TID[1082132800] PID[5874]...jestem wątkiem #2! TID[1090525504] PID[5874]...jestem wątkiem #3! TID[1098918208] PID[5874] tworzy wątek,... #4... PID[5874]...jestem wątkiem #4! TID[1107310912] 7

Specyfikacja parametru formalnego funkcji wątku typu void* może wydawać się dziwna i niewygodna, jest jednak jednym jaka może być zastosowana w tym celu w ramach C strukturalnego. W kolejnym przykładzie prześlemy, z procesu głównego do wątku potomnego, tablicę liczbową a tam zostanie wyznaczona wartość średnia jej elementów. Funkcja wątku może się przedstawiać w takim razie jak niżej void* thread( void* array ) int i; double sum,avg; Obliczamy sumę elementów tablicy, zwróćmy uwagę na konwersję typu wskazania (void*) na (double*) for( i=0,sum=0.0;i<n;i++ ) sum += *( (double*)array+i ); Wyznaczamy średnią arytmetyczną avg = sum/n; i wyprowadzamy na konsolę wynik printf( "wartość średnia: %16.10f\n",sum/(double)n ); return ( (void*)0 ); 8

Natomiast kod procesu głównego #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #define n 10000...rozmiar tablicy cóż można by też jak wcześniej int main( void ) int i; pthread_t tid; double x[n];... można też dynamicznie // double *x; // x = (double*) calloc( size_t n, sizeof( double ) ); // free( (void*)x ); for( i=0;i<n;i++ ) *(x+i) = ((double)rand())/(rand_max); printf( "wysyłam dane do wątku...[%d]\n",(int)tid ); pthread_create( &tid, NULL,thread,(void *)x ); printf( "...czekam na wątek\n" ); return 0; 9

No i teraz wykonanie (powiedzmy że skompilowano pod nazwą table) $./table wysyłam dane do wątku...[0]...czekam na wątek a wynik niezbyt budujący proces nadrzędny zakończył zanim wątek wykonał obliczenia. Można byłoby się ratować - przykładowo - użyciem sleep(), czyli zmodyfikujmy kod main(), dodając po printf() printf( "...czekam na wątek\n" ); sleep( 1 ); co wymusi oczekiwanie przez 1 sekundę. A efekt $./table wysyłam dane do wątku...[73419]...czekam na wątek wartość średnia: 0.4971322194 poprawny ponieważ tablicę zainicjowaliśmy z generatora zmiennych pseudolosowych rand(), normalizując od 0.0 do 1.0, to wartość średnia powinna wynieść dokładnie x= 1 2 Aczkolwiek sposób rozwiązania problemu nieco sztuczny i nienaturalny. 10

Jeżeli dzielimy większy problem na zadania i przekazujemy ich wykonanie wątkom, to powinniśmy zagwarantować że proces nadrzędny zaczeka aż wątek zakończy, w przeciwnym przypadku całość nie ma większego sensu. Stosowanie rozwiązań w rodzaju sleep() jest bardzo nieefektywne a bywa że i nie skuteczne. Służy temu m.in. funkcja phread_join(). SYNOPSIS #include <pthread.h> int pthread_join( pthread_t tid, void **code ); pthread_t tid identyfikator wątka, na który należy czekać void **code kod powrotu wątka (wartość z pthread_exit()) RETURN O,jeżeli, sukces (kod błędu w przeciwnym razie) Funkcja zawiesza, w razie potrzeby, wykonanie procesu (wątku) wywołującego pthread_join(), aż do momentu kiedy podany wątek tid zakończy działanie. 11

Teraz elementarna demonstracja użycia funkcji pthread_join(). #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> int main( void ) pthread_t tid; int rc; void* thread( void* ); Tworzymy nowy wątek rc = pthread_create( &tid, NULL,thread,NULL ); if( rc ) perror( "!.!.!...pthread_create()..." ); exit( 1 ); else if( pthread_join ( tid, NULL ) )... i próbujemy połączyć perror( "!.!.!...pthread_join()..." ); exit( 2 ); return 0; 12

Funkcja wątku po prostu wymusi odczekanie 5 sekund ma procesie nadrzędnym. void *thread( void *arg ) int i; printf( "...w wątku\n" ); fflush( stdout ); for ( i=0;i<5;i++ ) printf("\t%3d s\n",(i+1) ); fflush( stdout ); sleep(1); printf( "...i już koniec, zwracam sterowanie\n" ); fflush( stdout ); pthread_exit( NULL ); Wykonanie $./join...w wątku 1 s 2 s 3 s 4 s 5 s...i już koniec, zwracam sterowanie 13

Funkcja pthread_join(), ze swej natury, służy przyłączeniu jednego wątku co może stanowić pewnie problem jeżeli wątków będzie więcej. Załóżmy, że funkcja wątku jest następująca void *thread( void *n ) int i; double sum; printf("...wątek %3ld startuje...\n",(long)n ); fflush( stdout ); for( i=0,sum=0.0;i<n;i++ ) sum += sin((double)i)*sin((double)i) + cos((double)i)*cos((double)i) - 1.0; printf("...wątek %3ld zakończył...suma = %e\n",(long)n,sum ); fflush( stdout ); pthread_exit( NULL ); Zauważmy że wartością dokładną sumy jest zero, ponieważ zawsze sin( a ) 2 + cos( a ) 2 = 1 14

#include <stdio.h> #include <math.h> #include <pthread.h> #define T 10 #define N 100000 int main( void ) pthread_t threads[t]; int rc; long t; Uruchamiamy wątki for( t=0;t<t;t++) rc = pthread_create( &threads[t],null,thread,(void *)(t+1) ); if (rc) perror( "!.!.!...pthread_create()..." ); exit( 1 );... i zbieramy ponownie w całość for( t=0;t<t;t++) rc = pthread_join( threads[t],null ); if (rc) perror( "!.!.!...pthread_join()..." ); exit( 2 ); pthread_exit(null); 15

Jednym z kluczowych względów zastosowania wątków na gruncie współbieżności, prócz wymienionych na wstępnie, są kwestie efektywności. Cele oszacowania czasu wykonywania można wykorzystać komendę systemową time <command> podaje ona oszacowanie czasu dla procesu, z podziałem na składowe real, w przybliżeniu jest to real user + sys jednak w przypadku systemów multi-tasking, dodatkowo pracujących przy dużym obciążeniu real user + sys user, jest to czas kiedy CPU pozostawał w trybie user mode, a więc wykonywane były zakodowane instrukcje czy były wywołanie funkcji bibliotecznych typu printf(), malloc(), strlen(), fopen(), i podobnych; sys, jest to czas kiedy CPU pozostawał w trybie kernel mode, a więc wystąpiły wywołania funkcji systemowych w rodzaju open(), read(), write(), close(), wait(), exec(), fork(), exit(), i podobnych. Przykładowo: $ time sleep 5 real 0m5.006s user 0m0.000s sys 0m0.004s czyli uśpienie na 5 sekund zajęło de facto 5.006 sekundy, z czego na wywołania funkcji użytkownika wypadło 0 (bo ich nie było) a systemowych 4 milisekundy. Zauważmy, że pojawiły się też 2 milisekundy opóźnienia wynikła z faktu, że nie jest to w końcu jedyny proces obsługiwany przez system 16

Załóżmy że wykonamy określoną ilość razy funkcję. W celach testowania założymy, że będzie to funkcja, która wykonuje dodawanie 1 + 1 i podstawia pod zmienną rzeczywistą. Kod tego rodzaju funkcji może mieć postać void* task( void* arg ) double x; x = 1.0 + 1.0; return NULL; Celem porównania efektywności wątków i procesów funkcja task() wywołana będzie z dla zadanej ilości: procesów, będzie ona wykonywana przez potomka powołanego wywołaniem fork(); wątków, będzie to po prostu funkcja wątku, zadana w wywołaniu pthread_create(); 17

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <limits.h> int main( int argc,char** argv ) unsigned long i,n; int status; pid_t pid; if( argc>1 ) if( sscanf( argv[1],"%lu",&n )==1 ) for( i=0;i<n;i++ ) switch( (int)(pid=fork()) ) case -1: perror( "!.!.!...fork()..." ); exit( 1 ); break; case 0: task( NULL ); exit( 0 ); break; default: waitpid( pid,&status,0 ); else printf( "!.!.!...błędny argument [%s] wywołania [%s]\n",argv[1],argv[0] ); else printf( "!.!.!... %s [ilość < ULONG_MAX=%lu]\n",argv[0],ULONG_MAX ); return 0; W przypadku programu posługującego się procesami, kod przedstawiał się będzie następująco. 18

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <limits.h> int main( int argc,char** argv ) unsigned long i,n; pthread_t tid; if( argc>1 ) if( sscanf( argv[1],"%lu",&n )==1 ) for( i=0;i<n;i++ ) if( pthread_create( &tid, NULL,task,NULL ) ) perror( "!.!.!...fork()..." ); exit( 1 ); else pthread_join ( tid, NULL ); else printf( "!.!.!...błędny argument [%s] wywołania [%s]\n",argv[1],argv[0] ); else printf( "!.!.!... %s [ilość < ULONG_MAX=%lu]\n",argv[0],ULONG_MAX ); return 0; A teraz kod dla wątków 19

Prezentowane dalej wyniki dotyczą procesora AMD Turion(tm) 64 Mobile Technology MK-38 (2.2 GHz, BOGOMIPS: 1597.66) pracującego pod kontrolą Linux, kernel 2.6.18 Kompilacje wykonano przy użyciu GNU C compiler (gcc) ver 4.1.2 Intel C Compiler (icc) ver 10.1 Open64 Compiler Suite (opencc) ver 4.1 w każdym przypadku z opcją pełnej optymalizacji, czyli -O3...o jednak tutaj wiele nie wniesie. 20

time, [s] 1500 1250 1000 750 500 250 0 real user sys 0,33 1,58 11,81 fork(), dla gcc 109,69 1000 10000 100000 1000000 10000000 Ilość, [-] 1146,64 21

time, [s] 150 125 100 75 50 25 0 real user sys 0,05 0,36 1,54 pthread_create(), dla gcc 14,13 1000 10000 100000 1000000 10000000 Ilość, [-] 127,43 22

Interesujące może być na ile efektywnie zarządza procesami i wątkami wynikowy kod trzech testowanych tu kompilatorów. time, [s] 200 150 100 50 0 109,69 fork(), dla 1 miliona 174,51 116,09 gcc icc open64 Kompilator real user sys time, [s] 20 15 14,13 10 5 0 pthread_create(), dla 1 milona 12,99 13,11 gcc icc open64 Kompilator real user sys 23