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

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

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

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

Programowanie Współbieżne

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

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

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

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

Wstęp do Programowania, laboratorium 02

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

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

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

1 Zapoznanie się ze środowiskiem Xenomai.

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

Tablice, funkcje - wprowadzenie

Model procesu w systemie Linux. Tomasz Borzyszkowski

Wstęp do programowania

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!

Metody Metody, parametry, zwracanie wartości

3 Przygotował: mgr inż. Maciej Lasota

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

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

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

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

4.2 Sposób korzystania z l acza

Wykład 1

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

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

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

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

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Część 4 życie programu

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

1 Podstawy c++ w pigułce.

Programowanie Proceduralne

4. Procesy pojęcia podstawowe

Obsługa plików Procesy

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

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

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

Język C zajęcia nr 11. Funkcje

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

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

Pobieranie argumentów wiersza polecenia

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

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

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

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

Wskaźniki w C. Anna Gogolińska

4. Procesy pojęcia podstawowe

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

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

Procesy. S. Samolej: Procesy

2. Zarządzanie procesami

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

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

2 Przygotował: mgr inż. Maciej Lasota

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

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

Programowanie - wykład 4

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

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ęć

Zarządzanie Procesami

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

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

1 Podstawy c++ w pigułce.

Podstawy programowania w języku C++

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

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

PROGRAMOWANIE w C prolog

Aplikacja Sieciowa wątki po stronie klienta

Wskaźniki. Informatyka

Wielozadaniowość w systemie Microsoft Windows

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk

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

Wskaźniki. Programowanie Proceduralne 1

Uzupełnienie dot. przekazywania argumentów

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

Systemy Operacyjne - Operacje na plikach

Programowanie procesorów graficznych NVIDIA (rdzenie CUDA) Wykład nr 1

I - Microsoft Visual Studio C++

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

Struktury czyli rekordy w C/C++

Łącza nienazwane(potoki)

Biblioteka standardowa - operacje wejścia/wyjścia

Podstawy programowania komputerów

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 chili jego tworzenia przypisywane jest unikalne pid_t id; tak też i wątkowi pthread_t id; Wątek może pobrać swój identyfikator wywołaniem #include <pthread.h> pthrad_t pthread_self(void); Wątek tworzony jest 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. #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 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ększe zadanie na podzadania 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 wymusza 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. Funkcja wątku niech będzie 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ładna sumy jest zero, ponieważ zawsze sin 2 cos 2 = 1 14

Natomiast część główna. #include <stdio.h> #include <stdlib.h> #include <math.h> #include <pthread.h> //#include <limits.h>...definicja INT_MAX #define T 10 #define N 100000 //#define N INT_MAX...dla chcących sprawdzić wentylator int main( void ) pthread_t threads[t]; int rc; long t; W dalszej części pozostaje na rozesłać i przyłączyć ponownie do procesu głównego 15

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); 16

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. Aby dokonać takiej oceny napiszemy dwa programy, które uruchomią identyczną ilość procesów oraz wątków i porównamy czasy jakie zużyje na to system. Cele określenia czasu wykonywania wykorzystamy 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. 17

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. Załóżmy że oba programy wywołają funkcję jak niżej void* task( void* arg ) double x; x = 1.0 + 1.0; return NULL; Typ dla funkcji i parametru formalnego, wybrano tak aby uzyskać zgodność z pthread_create(), przy czym dla: 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(); 18

#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. 19

#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 20

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 z opcją -O3 czyli pełnej dostępnej optymalizacji (co jednak tutaj wiele nie wniesie). 21

time, [s] 1400 1200 1000 800 600 400 200 0 real user sys fork(), dla gcc 0,326 1,581 11,806 1000 10000 100000 1000000 10000000 Ilość, [-] 109,69 1146,638 22

time, [s] 140 120 100 80 60 40 20 0 real user sys pthread_create(), dla gcc 0,047 0,355 1,536 14,125 1000 10000 100000 1000000 10000000 Ilość, [-] 127,433 23

Interesujące może być na ile efektywnie zarządza procesami i wątkami wynikowy kod trzech testowanych tu kompilatorów kompilatorów. time, [s] 200 180 160 140 120 100 80 60 40 20 0 109,69 fork(), dla 1 miliona 174,513 116,087 gcc icc open64 Kompilator real user sys time, [s] 20 18 16 14 12 10 pthread_create(), dla 1 milona 8 6 4 2 0 14,125 12,985 13,106 gcc icc open64 Kompilator real user sys 24