Pthreads Em C
Short Description
Download Pthreads Em C...
Description
Uma introdu¸c˜ cao a˜o a Pthreads em linguagem C Guilherme O’Connor de Lungarzo Junho de 2003
Sum´ ario 1 Aloca oca¸ c˜ cao a ˜o de mem´ oria
2
2 O que ´ e uma thread?
4
3 O que s˜ ao PThreads?
6
4 Criando PThreads
6
5 Passando Argumentos para PThreads
8
6 Juntando e controlando PThreads
9
7 O uso de mutex
13
8 O uso uso de vari´ ari´ aveis aveis de condi¸ c˜ ao
16
Nota A primeira se¸c˜ cao a˜o deste documento trata de aloca¸ c˜ cao a˜o de mem´ oria oria para programas escritos em C, o leitor que conhe¸ c a bem este assunto, pode pular ca diretamente para a segunda se¸c˜ c˜ao, ao, sem preju pre ju´´ızos. ızo s. Este texto text o ´e distribu distri bu´´ıdo junto com o arquivo arqui vo programas.tgz programas.tgz que qu e cont´ co nt´em em todos os c´ odigos fonte dos programas exibidos em exemplos neste texto. odigos
1
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
1
Aloca¸ c˜ c˜ ao de mem´ em ´ oria oria
Quando executamos um programa que foi escrito em C, o sistema operacional carrega na mem´ oria o ria o c´odigo odigo execut´ avel do programa em uma area avel a´rea da mem´oria. oria. A esta area ´area damos o nome de ´ area de texto. Em seguid s eguidaa ´e aloca al ocada da mem´oria oria para todas as vari´ aveis aveis globais, e ent˜ao ao uma area a´rea para as vari´ aveis aveis que s˜ ao ao declaradas pela fun¸c˜ cao a˜o principal do programa, fun¸c˜ cao main a˜o main.. Esta Es ta ´e ´ de dados . chamada de area Depois, inicia-se a execu¸c˜ c˜ao ao do programa, programa, isto ´e feito porque p orque o sistema operacional guarda um ponteiro para a area a´rea de texto, de onde retira o c´ odigo odigo execut´avel avel e o envia para o processador, que se encarrega da execu¸ c˜ao. ao. O program pr ogramaa tamb´ t amb´em em possui p ossui uma pilha que ´e chamada cha mada de pilha de execu¸c˜ cao ˜ , que ´e onde o sistema sistema operacional guarda as informa¸ informa¸ c˜ oes o es a respeito do estado do programa (valores dos registradores, ponteiros para instru¸ c˜oes, oes, etc.) quando a fun¸c˜ cao a˜o suspende sua execu¸c˜ cao. a˜o. O programa pode suspender sua execu¸c˜ c˜ao ao por diversos motivos, o mais obvio ´obvio ´e que em um sistema sistema multitarefa multitarefa preemptivo o sistema sistema operacional distribui fatias de tempo para cada processo, ou seja, cada instˆ ancia ancia de um programa em execu¸c˜ cao. a˜o. Quando Quando o tempo tempo ao qual o proces processo so tinha tinha direi direito to se esgota, o sistema operacional, guarda o seu estado na pilha e o suspende, colocando outro processo em execu¸ c˜ cao. a˜o. Isto Isto ´e feito feito exatame exatament ntee do modo inverso, os valores na pilha de execu¸c˜ cao ˜ao deste processo s˜ ao ao restaurados e o programa ´e posto para rodar. Outra maneira de uma fun¸c˜ cao a˜o ter sua execu¸c˜ cao a˜o suspensa susp ensa ´e quando q uando ela faz uma chamada a outra fun¸c˜ c˜ao, ao, o estado dela ´e guardado na pilha, mem´ oria oria ´e alocada aloc ada para a area a´rea de dados da fun¸c˜ cao, a˜o, o sistema operacional guarda um ponteiro para o lugar, na area a´rea de texto, onde est´ a o c´ odigo odigo execut´ avel avel do programa e a execu¸c˜ cao a˜o come¸ca. c a. Anal Analog ogame ament ntee ao que ocorre ocorre com o main o main,, que afinal afina l de contas tamb´em em ´e uma fun¸ c˜ c˜ao. ao. Sempre que uma fun¸c˜ cao a˜o chama outra os dados desta s˜ ao ao armazenados na pilha, em espera, e uma nova linha de execu¸c˜ c˜ao ao ´e criada. cr iada. Observe por p or exemplo o seguinte programa: fatorial.c 1
# include include
2 3 4 5 6
int fatori fatorial(in al(int t a){ int fat=1; fat=1; if(a>1) fat = a * fatori fatorial( al(a-1 a-1); );
2
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
7
fat fat = 1; return return fat;
8 9 10
else
}
11 12 13 14 15 16 17
int main(){ main(){ int fat,a; fat,a; scanf("%d",&a); fat = fatorial( fatorial(a); a); printf("%d",fat); }
No in´ in´ıcio da execu¸ exe cu¸c˜ c˜ao ao o c´ odigo odigo compilado do programa ´e colocado na area ´ de texto, depois, a mem´ oria oria correspondente as a`s vari´aveis aveis fat e a ´e sepa se para rada da,, criando a area a´rea de dados da fun¸c˜ c˜ao ao main e e o processo come¸ca ca a ser executado. Ao chegar a` atribui¸c˜ cao a˜o na linha 13 o valor de de fatorial(a) deve ser avaliado antes de ser atribu atrib u´ıdo a fat. fat. Isto ocorre suspendendo-se a execu¸c˜ cao a˜o da main , guardando seu contexto, e repetindo o procedimento para a fun¸c˜ cao a˜o fatorial. fatorial. Cria Cria-s -see a ´area area de dados para guardar a vari´ avel fat avel fat,, recupera-se o c´ odigo odigo execut´ avel avel na area a´rea de texto e executa-se a fun¸c˜ cao, a˜o, que, eventualmente, vai ser interrompida por outra instˆancia ancia da fun¸c˜ cao fatorial a˜o fatorial que que ap´ os os sua execu¸c˜ cao a˜o vai permitir a retirada da fun¸c˜ cao a˜o no topo da pilha e assim sucessivamente. O programa acima, ´e tipicamente seq¨ uencial, uencial, j´ a que cada vez que uma chamada de fun¸c˜ c˜ao ao ´e feita o programa depende deste valor para continuar sua execu¸c˜ cao. a˜o. Mas tome por exemplo o seguinte programa1 : hipotenusa.c 1 2
#include #include
3 4 5 6 7 8
int quadra quadrado(in do(int t a){ int quad; quad; quad quad = a*a; a*a; return return quad; }
9 10 11
int main(){ main(){ int hip, hip_quad; hip_quad; 1
O leitor observar´a que os programas aqui exibidos levam uma s´ erie erie de etapas desnecess´ arias, arias, todo o c´alculo alculo da hipotenusa poderia po deria ter sido feito em uma linha, por´ p or´ em, em, motivos did´ aticos justificam esta constru¸c˜ aticos c˜ao. ao.
3
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
12 13 14
15 16 17 18
19 20
int cateto1,cateto1_quad; cateto1,cateto1_quad; int cateto2, cateto2, cateto2_qu cateto2_quad; ad; scanf("%d %d",&cateto1,&cateto2); %d",&cateto1,&cateto2); cateto1_quad=quadrado(cateto1); cateto2_quad=quadrado(cateto2); hip_quad hip_quad = cateto1_q cateto1_quad uad + cateto2_qu cateto2_quad; ad; hip = sqrt(hip_ sqrt(hip_quad) quad); ; printf("%d\n",hip);
}
Quando a primeira chamada a` fun¸c˜ cao quadrado a˜o quadrado2 ´e executada execu tada na linha 15, o seu resultado s´ o ser´ a necess´ ario na linha 17. Isto quer dizer que n˜ ario ao ao haveria necessidade de interromper a execu¸ c˜ cao a˜o da linha 16, enquanto a fun¸c˜ cao a˜o executa embora seja isto que acontece.
2
O que ´ e uma thre thread? ad?
Em um programa em C, poder po der´´ıamos executar executa r as chamadas a fun¸ c˜oes oes concorrentemente, se pud´essemos essemos conseguir co nseguir que o sistema operacional operaciona l criasse uma nova linha de execu¸c˜ c˜ao, ao, de certa maneira um novo processo. pro cesso. Isto ´e poss´ poss´ıvel nos sistemas operacionais modernos atrav´es es do suporte a threads, threa ds, uma thread ´e um pro pr o cess ce ssoo que qu e cont´ co nt´em: em : •
PID (Process (Process ID);
•
pilha de execu¸c˜ c˜ao; ao;
•
registradores;
•
propriedades de escalonamento
Como a thread ´e a execu¸ c˜ ao a o de uma fun¸c˜ cao, a˜o, ela precisa ter acesso ao c´odigo odigo execut´ avel a vel na area a´rea de texto, bem como as a`s vari´aveis aveis glob globais ais.. Pa Para ra conseguir isto, o sistema operacional cria a thread como um processo que mant´em em os mesmos ponteiros para a area a´rea de dados globais, e um ponteiro para o lugar, dentro da area a´rea de texto, onde est´ a o c´ odigo odigo da fun¸c˜ cao. a˜o. 2
N˜ ao ao se esque¸ca ca que para compilar este programa com o gcc e´ nece ne cess ss´´ario ario passar o argumento -lm
4
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Al´em em disto, para que a thread possa receber parˆ ametros ametr os ela mant´em em um unico u ´nico ponteiro para um bloco cont´ cont´ıguo de mem´ oria que cont´em em uma struct com todos seus argumentos. Em linguagem C, um ponteiro guarda um endere¸co co de mem´ oria o ria e o formato dos dados armazenados em tal ponteiro, por exemplo, quando fazemos, 1 2 3
int int a; int *ponteiro *ponteiro; ; pontei ponteiro ro = &a;
estamos n˜ ao ao s´o armazenando o lugar onde a vari´ avel avel a est´ a sendo guardada, mas tamb´ tamb´em em quantos quantos bytes ocupa, podendo assim usar a constru¸ c˜ao *ponao *ponteiro; de teiro; de maneira maneir a idˆentica entica a` vari´avel avel a. Existe, no entanto, uma maneira de se ter um ponteiro n˜ ao ao formatado, ou seja, uma vari´avel avel que guarde pura e simplesmente um endere¸ co co da mem´oria, oria, sem ter nenhuma informa¸c˜ c˜ao ao a respeito do formato dos dados ali guardados. Um ponteiro p onteiro deste de ste tipo ´e declarado como 1
void *ponteiro *ponteiro
Embora possa p ossa parecer parec er estranho estran ho a primeira vista, ele ´e um velho conhecido de qualquer programador C. A fun¸c˜ cao malloc a˜o malloc ´ ´e uma um a fun¸ fu n¸c˜ cao ˜ao que retorna meramente um endere¸co co de mem´oria. oria. O in´ in´ıcio de um bloco blo co cont´ cont´ıguo de mem´ oria, oria, n˜ao ao formatado, que foi reservado para a fun¸ c˜ cao ˜ao que a chamou. ´ s´ E o lembrar que a fun¸c˜ c˜ao ao malloc, malloc, recebe como unico u´nico argumen argumento to um n´umero u mero intei inteiro. ro. O fato de, freq¨ freq¨ uentemente, usarmos a fun¸c˜ uentemente, cao a˜o sizeof sizeof para determinar este n´ umero umero n˜ ao altera o fato de que a fun¸ ao c˜ c˜ao malloc ao malloc n˜ao ao recebe nenhuma informa¸c˜ c˜ao ao a respeito dos dados que ser˜ ao ao armazenados l´ a. a. Outro esclarecimento que se faz necess´ ario ario ´e que em C, o nome de uma fun¸c˜ cao a˜o representa o endere¸co co de mem´ oria, oria, dentro da area a´rea de texto, no qual o c´odigo odigo execut´ avel avel referente a ela est´ a localizado. Assim, a thread pode receber o ponteiro para sua area a´rea de texto (que ´e um subconjunto da area a´rea de texto do programa) a partir do nome da fun¸ c˜ c˜ao. ao. Em sistemas operacionais modernos, nem todo o c´ odigo odigo execut´ avel avel ´e carca rregado de uma vez na area a´rea de texto, no entanto o sistema se encarrega destes detalhes e fornece um endere¸ camento cament o que ´e v´ alido para fins de uso do proalido grama.
5
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
3
O que s˜ ao ao PThread PThreads? s?
Pthreads ´e um apelido para Posix Threads. Threads. Posix , Portable Operating System, Interface for Unix , ´e um padr pa dr˜ a˜o, definido pela IEEE (Institute of Elecao, trical and Electronics Engineers) e pela ISO (International Organization for Standartization), como o pr´ oprio oprio nome diz ´e um u m padr˜ p adr˜ ao ao que define define como, no mundo do *nix os programas devem devem ser interfaceados, interfaceados, visando portabili p ortabilidade. dade. Ocorre que inicialmente, cada fabricante de hardware tinha seu pr´ oprio oprio padr˜ ao de threads, o que fazia com que programas multithreaded (ou seja, ao programas usando threads) fossem muito pouco p ort´ aveis de plataforma para plataforma.
4
Crian riando do PThr PThrea eads ds
Fazer uma chamada a uma pthread n˜ ao ao ´e muito diferente d iferente de fazer uma chamada a uma fun¸c˜ c˜ao. ao. De fato, um programa programa “Hello “Hello World World””3 pode ser feito da seguinte maneira. hellosequencial.c 1
#include
2 3 4 5
void hello(){ hello(){ printf("Hello World\n"); }
6 7 8 9
int main(){ main(){ hello(); } hellothreaded.c
1 2
#include #include
3 4 5 6
void *hello(){ *hello(){ printf("Hello World\n"); }
7 8 9
int main(){ main(){ pthread_t pthread_t id; 3
Como (quase) todo mundo sabe, um “Hello World” ´e um programa (normalmente o primeiro primeiro programa feito dentro dentro de um paradigma) paradigma),, e tudo o que ele faz ´e dizer “Hello World” com pequenas varia¸c˜ c˜oes oes
6
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
pthrea pthread_c d_crea reate( te(&id &id , NULL NULL , hello hello , NULL); NULL);
10 11 12
}
Para compilar e executar execu tar este programa com o gcc, vocˆe deve fornecer fo rnecer os comandos gcc hellothre hellothread.c ad.c -o hellothrea hellothread d -lpthread -lpthread ./hellothread
Os quatro parˆ ametros ametros para a fun¸c˜ c˜ao pthread ao pthread create s˜ao: ao: 1. o endere¸co co do identificador da thread; 2. o endere¸co co dos atributos; 3. o ende endere¸ re¸ co co do c´odigo odigo a executar (passado, como vimos, atrav´es es do nome da fun¸c˜ cao); a˜o); 4. o endere¸co co da estrutura de argumentos. No entanto, apenas o primeiro e terceiro argumentos s˜ ao ao obrigat´ orio o rios. s. O primeiro, porque a fun¸c˜ c˜ao ao vai tentar escrever nele, caso NULL caso NULL seja seja passado, haver´a um acesso inv´ alido alido de mem´oria. oria. O terceiro, terceiro, porque ela tentar´ tentara´ executar o c´ odigo odigo no endere¸co c o passa passado do.. Se o endere endere¸ co c¸o for inv´alido alido o mesmo problema ocorrer´ a. a. ´ importante levar E levar em conta que a fun¸ c˜ao pthrea ao pthread d create retorna create retorna um valor inteiro inte iro que ´e o c´ odigo de erro encontrado na cria¸ odigo c˜ c˜ao ao da thread, ou zero, caso contr´ ario. ario. Tamb´em em ´e importante impo rtante levar em conta que as threads thre ads s´ o existem enquanto enquanto a thread principal existir, a menos que a fun¸c˜ c˜ao pthread ao pthread exit seja exit seja usada. Esta fun¸c˜ cao a˜o leva um argumento que ´e um ponteiro para o valor de status da thread. thre ad. Convenciona-se que um processo que finalizou sua execu¸c˜ cao a˜o adequadamente adequadamente deve retornar 0, enquanto que quando um erro ocorre, um valor diferente de
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
6 7
pthread_exit(NULL);
}
8 9 10 11 12 13 14 15 16
int main(){ main(){ pthread_t pthread_t id; int status; status; status status = pthrea pthread_c d_crea reate( te(&id &id , NULL NULL , hello hello , NULL); NULL); if(status!=0) exit(-1); pthread_exit(NULL); }
5
Passa assand ndo o Argu Argume men ntos tos para para PTh PThre read adss
Podemos fazer uma varia¸c˜ cao a˜o do “Hello World” com um la¸co co que execute um n´umero umero arbitr´ ario de threads, neste caso seria mais interessante que cada ario thread imprimisse algo como: “Eu sou a thread i de n” Note que para saber o valor de n de n ´ ´e muit muitoo f´acil, acil, basta a vari´avel avel ser global, j´a o mesmo n˜ ao pode ser feito com a vari´ ao avel i avel i porque porque ela est´ a constantemente sendo alterada pela thread executando o main o main.. Assim quando uma determinada thread for criada, digamos com i = 3, ela pode n˜ao ao ler imediatamente o valor de i, mas fazˆe-lo e-lo um pouco mais tarde ta rde quando qua ndo o main o main j´ j´a a alterou. O ametro. ametro. i deve ser passado como parˆ Para fazer isto, basta passar para a thread o endere¸ co do local onde o valor de i foi armazenado, para tal, deve existir um local de armazenamento para estes valores onde eles n˜ ao a o mudem mudem.. Como Como por exempl exemploo um vetor vetor de argumentos. Onde cada argumento ´e um struct. argumentos.c 1 2 3
#include #include #define #define MAX_THR MAX_THREADS EADS 100 100
4 5
typedef typedef struct struct _ARGS{ _ARGS{
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
14 15
16 17
prin printf tf(" ("Eu Eu sou sou a thre thread ad %d de %d\n %d\n", ", i, n); n); pthread_exit(NULL);
}
18 19 20 21 22 23
int main(){ main(){ int int i; ARGS args[MAX_THREADS]; args[MAX_THREADS]; int status; status; pthread_t id[MAX_THREADS];
24 25
26 27 28 29 30 31 32 33
34 35
printf("Qu printf("Quantas antas Threads? Threads? "); scanf("%d",&n); for( for(i= i=0 0 ; iid; id;
17
/* soma soma N nume numero ros s alea aleato tori rios os entr entre e 0 e MAX MAX */ for( for(i= i=0 0 ; i%d]",i,status); }
46 47 48 49 50 51 52 53 54 55 56
/* conc conclu lui i a soma soma */ printf("\nSomando printf("\nSomando parcelas:"); for(i= for(i=0 0 ; i< N_THRE N_THREADS ADS ; i++){ i++){ printf(" [%d]", soma_parcial[i]); soma_parcial[i]); somatotal somatotal += soma_parci soma_parcial[i] al[i]; ; }
57 58 59 60 61 62 63
/* imprim imprime e o result resultado ado */ printf("\nSoma total: %d\n",somatotal); %d\n",somatotal);
64 65 66
67 68
pthread_exit(NULL);
}
O objetivo do la¸co co entre as linhas 48 e 55 ´e esperar esp erar a execuc˜ execuc˜ao ao de todas as
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
thread mais complexa poderia retornar valores diferentes testados pelo main para exibir exibir mensagens mensagens de erro ou outras atitudes a crit´ erio erio do programador. programador. No entanto, e ntanto, nem sempre sempr e ´e poss p oss´´ıvel juntar junt ar threa t hreads. ds. O segundo seg undo argumento argum ento passado para pthread para pthread create ´ u m atribut at ributoo que qu e pode p ode ser joinable ser joinable ou ou detached. create ´e um detached. Para que uma thread possa ser juntada ela tem que ser do tipo joinable tipo joinable,, que ´e o default do Posix. Mas, cuidado, isso n˜ao ao garante que toda implementa¸c˜ cao a˜o siga essa orienta¸c˜ cao. a˜o. Asim, ´e sempre se mpre uma boa b oa id´eia eia explicit e xplicitar ar que qu e uma um a thread th read ´e joinab joi nable, le, quando qua ndo isto ist o ´e desej´ des ej´ avel. avel. Isto faz faz o c´ odigo odigo mais port´ avel avel e menos propenso a ter problemas. Para fazer isto ´e necess´ ario criar uma vari´ avel a vel do tipo pthread attr t, t, inicializ´a-la a -la com a fun¸c˜ c˜ao ao pthread attr init e fazˆ e-la e-la joinable joinable com a fun¸ c˜ cao a˜o pthread pthread attr setdetachstat setdetachstatee. Finalm Finalmen ente te esta vari vari´ a´vel de atributo pode ser avel passada como parˆ ametro a metro para a fun¸c˜ c˜ao ao pthread create. seguin inte te c´ codigo o´digo create. O segu intercalado adequadamente no programa somaaleat.c programa somaaleat.c faria faria o servi¸co. co. 1 2 3 4
pthread_attr_t atributo; pthread_attr_init(&atributo); pthread_attr_setdetachstate(&at pthread_attr_setdetachstate(&attr, tr, PTHREAD_CREATE_JOINABLE); PTHREAD_CREATE_JOINABLE); pthread_create(&id[i], pthread_create(&id[i], atributo, atributo, realiza_soma, realiza_soma, &args[i]); &args[i]);
Quando uma thread ´e joinable, joinable, isto significa significa que ap´ os sua execu¸c˜ c˜ao ao a mem´oria oria ocupada por ela n˜ ao ao ´e liberada libe rada de imediato, imedia to, isto ´e feito ap´ os os o join, quando a thread principal j´ a recuperou o valor de status.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
7
O uso de mutex
No programa somaaleat.c cada thread escrevia em uma posi¸c˜ cao a˜o diferente diferente do vetor soma parcial, parcial, por isso n˜ao ao havia havia problemas problemas de concorrˆ concorrˆencia, encia, mas imagine o caso onde mais de uma thread precisa acessar a mesma vari´ avel. avel. Ler a mesma vari´ avel avel n˜ao ao tem problema, mas quando desejamos alter´ aala, precisamos levar em conta que isto pode requerer (e normalmente requer) mais de uma instru¸c˜ c˜ao ao de m´ aquina. Vamos assumir, por exemplo, que sejam aquina. necess´arios arios os seguintes passos para alterar uma vari´ avel: avel: 1. Ler o valor valor da vari´ vari´ avel, avel, 2. Alterar o valor valor da vari´ vari´ avel avel localmente, 3. Recolocar o valor valor da vari´ vari´ avel. avel. Em um sistema preemptivo, como a maioria dos sistemas modernos, um processo pode perder o processador a qualquer qualquer momento momento sem pr´evio evio aviso, portanto, se duas threads est˜ ao ao tentando alterar a mesma vari´ vari´ avel pode ocorrer a interrup¸c˜ c˜ao ao da primeira, gerando inconsistˆencia encia de dados. Por exemplo, imagine que uma vari´avel avel x compartilhada, inicialmen inicialmente te valendo 0 v´a ser alterada por duas threads A e B, que guardam localmente o valor de x em vari´ aveis aveis locais a e b, respecti respectiv vamente. amente. Poderia Poderia ocorrer o seguinte.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
vari´avel avel mutex como parˆametro, ametr o, ´e chamada, chamada , o valor do mutex ´e verificado verifica do e uma de duas atitudes ´e tomada: 1. se o mutex est´a destravado, ent˜ ao trava ele e continua a execu¸c˜ ao cao; a˜o; 2. se o mutex est´a travado, espera ele mudar de estado, trava e continua e execu¸c˜ c˜ao. ao. Assim se mais de um processo deve acessar a mesma vari´avel, avel, podemos proteger a parte do c´ odigo o digo que n˜ao ao deve ser executada simultaneamente, chamada de regi˜ ao cr´ıtica ıt ica , com com um mutex mutex.. Assi Assim, m, o prime primeir iroo process processoo a alcan¸car car o mutex trava ele, e os seguintes, ao atingirem a regi˜ ao ao cr´ıtic ıt icaa s˜ao ao mantidos em espera pela fun¸c˜ c˜ao pthread ao pthread mutex lock at´ lock at´e que o valor val or do mutex mute x mude. Isto s´o vai ocorrer quando, ao sair da regi˜ ao ao cr´ cr´ıtica, a tread que obteve o mutex chamar a fun¸c˜ cao pthread a˜o pthread mutex unlock, unlock , que se encarrega de destravar o mutex. Apenas a thread que possui o lock pode destrav´ a-lo. Em seguida, o primeiro processo escalonado ap´ os o destravamento, trava os o mutex e entra na se¸c˜ cao a˜o cr´ cr´ıtica, mantendo ma ntendo os outros processos em espera. e spera. Antes Antes de ser ser usado usado,, o mutex mutex deve deve ser ser inic inicia iali lizad zado, o, isto isto pode ser ser feito feito estaticamente estaticamente,, durante durante a declara¸ c˜ao a o da vari´avel, avel, atrav´es es de um comando como 1
meu_mutex = PTHREAD_MUTEX_INITIALI PTHREAD_MUTEX_INITIALIZER; ZER;
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Outra Outra coisa coisa que que pode, em um prim primei eiro ro mome moment nto, o, passa passarr pela pela nossa nossa cabe¸ca, ca, ´e que as threads podem p odem ser detached , j´a que cada uma vai se encarregar de somar sua parcela ao total. Isto ´e verdade, mas conv´ em em n˜ ao se esquecer que em e m geral gera l vamos querer que algu´ a lgu´em em imprima o resultado. resu ltado. Claro que podemos criar uma estrutura para que cada thread descubra se ´e a ultima u´ltima e, caso seja, se encarregue de imprimir o resultado, mas tal cria¸c˜ c˜ao ao ´e uma complic com plica¸ a¸c˜ c˜ao a o do c´ odigo odigo e desnecess´ aria dentro do escopo deste aria texto. O seguinte programa implementa as modifica¸c˜ coes o˜es discutidas, note que este programa implementa tamb´em em a declara¸ c˜ cao a˜o expl´ expl´ıcita das threads thre ads como joinable. Fica a cargo do leitor implemetar a vers˜ ao detachable , caso deseje. somamutex.c 1 2 3
#define #define N_THREA N_THREADS DS 10 #defin #define e N 100000 100000 #defin #define e MAX MAX 10
4 5 6 7
typedef typedef struct struct _ARGS{ _ARGS{ int id; }ARGS;
8 9 10
pthread_mutex_t meu_mutex = PTHREAD_MUTEX_INITIALIZER;; PTHREAD_MUTEX_INITIALIZER;; int somatotal somatotal=0; =0;
11 12 13
void *realiza *realiza_soma _soma(void (void *p){ *p){ int resultado resultado=0, =0, i;
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
pthread_attr_t atributo; ARGS args[N_THREADS];
32 33 34 35 36 37
/* inicializ inicializando ando atributo atributo */ pthread_attr_init(&atributo); pthread_attr_setdetachstate(&at pthread_attr_setdetachstate(&atributo, ributo, PTHREAD_CREATE_JOINABLE); PTHREAD_CREATE_JOINABLE);
38 39 40 41 42 43 44 45 46 47 48 49 50
/* cria cria cada cada uma uma das das thre thread ads s */ printf("\nCriando printf("\nCriando threads:"); for(i= for(i=0 0 ; i< N_THRE N_THREADS ADS ; i++){ i++){ args[i args[i].i ].id d = i; rc = pthread_cr pthread_create( eate(&id[ &id[i], i], &atributo &atributo, , realiza_soma, &args[i]); if (rc){ (rc){ printf("\n printf("\nErro Erro %d na cria¸ c~ cao\n",rc); a ~o\n",rc); exit(-1); } printf(" [%d]",i); }
51 52 53 54 55 56 57 58
/* junt junta a cada cada uma uma das das thre thread ads s */ printf("\nJuntando printf("\nJuntando threads..."); for(i= for(i=0 0 ; i< N_THRE N_THREADS ADS ; i++){ i++){ rc = pthread_jo pthread_join(id in(id[i], [i],(void (void **)&statu **)&status); s); if (rc){ (rc){ printf("\n printf("\nErro Erro %d na jun¸ c~ cao\n",rc); ~ ao\n",rc); exit(-1);
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
de fazer a chamada a pthread a pthread mutex lock. lock. Mais Mais que isso, uma simples simples veriverifica¸c˜ c˜ao a o n˜ao ao ´e suficiente, mas uma verifica¸ c˜ cao a˜o peri´ odica odica at´e que a condi¸c˜ cao a˜o seja satisfeita. satisfeita. Chamamos este tipo de constru¸c˜ cao a˜o de Busy Waiting e, como o pr´oprio oprio nome diz, mant´em em o processo ocupado fazendo nada. Isto ´e ruim pois p ois conc onsome recursos computacionais sem trazer nenhum benef b enef´´ıcio. ´ E para evitar este desperd´ desperd´ıcio que s˜ ao ao definidas as vari´ aveis aveis de condi¸c˜ c˜ao. ao. Uma vari´avel avel de condi¸c˜ c˜ao ao ´e equivalent equivalentee a um recurso pelo p elo qual o processo espera e entra em uma fila, como uma fila do spooler de impress˜ ao ao ou similar. Para entrar nesta fila, o processo faz uma chamada wait chamada wait sobre a vari´ avel avel e fica esperando sua vez. Em contrapartida, uma outra thread sabe que a primeira thread est´ a, a, ou pode estar esperando por este recurso, ent˜ ao, quando considera a condi¸c˜ ao, cao a˜o satisfeita faz uma chamada signal chamada signal sobre sobre a vari´ avel, que sinaliza um processo avel,
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
cr´ cr´ıtica para verificar sua condi¸ c˜ cao, a˜o, o que ´e feito feito chama chamando ndo a fun¸ c˜ao ao pthread cond wait. wait. Esta fun¸c˜ c˜ao ao realiza realiz a trˆes es opera¸ op era¸c˜ coes o˜es atomicamente: 1. destrav destrava o mutex 2. espera, propriamente, propriamente, ser sinalizado sinalizado 3. trava trava o mutex Por isto ist o ´e necess nec ess´ ario a´rio que ela receba, no seu segundo parˆ ametro, o endere¸co co do mutex que ela deve alterar. Deste modo, olhando a certa distˆ ancia, tudo se passa como um mutex ancia, normal. No entanto olhado mais de perto vemos que ´e necess´ ario ario que o mutex mutex seja destravado destravado e travado travado dentro da espera, pois p ois isso ´e o que permite p ermite que a outra thread altere a condi¸c˜ cao a˜o pela qual a primeira thread est´ a esperando. No programa seguinte, prodcons.c, temos um caso trivial de produtor/con-
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
24 25 26 27 28 29
void *consumidor(){ pthread_mutex_lock(&meu_mutex); pthread_cond_wait(&minha_cond, pthread_cond_wait(&minha_cond, &meu_mutex); printf("Va printf("Valor lor do recurso: recurso: %d\n",recu %d\n",recurso) rso); ; pthread_mutex_unlock(&meu_mutex); }
30 31 32
int main(){ main(){ pthread_t pthread_t prod_id, prod_id, cons_id; cons_id;
33 34 35
/* inicia inicializ liza a o gerado gerador r de numero numeros s aleato aleatorio rios s */ srand(time(NULL));
36 37 38 39 40
/* inicia inicializ liza a mutex mutex e cond cond */ pthread_mutex_init(&meu_mutex, pthread_mutex_init(&meu_mutex, NULL); pthread_cond_init(&minha_cond, pthread_cond_init(&minha_cond, NULL);
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Trusted by over 1 million members
Try Scribd FREE for 30 days to access over 125 million titles without ads or interruptions! Start Free Trial Cancel Anytime.
Produtor
Consumidor
Dorme 3s
Entra na RC Espera sinal, destravando RC
Acorda Atualiza recurso Sinaliza Destrava RC Termi ermin na
Rec Recebe ebe sina sinal, l, trav travan ando do RC Imprime o valor Destrava RC Termina
Sugest˜ao ao para o leitor: modifique o programa, comentando as linhas 13, 18 e 26, eliminando o sincronismo e a espera, e execute o programa, o valor fica quase imprevis imprevis´ıvel, ıvel, depende de quem travar travar o mutex primeiro. primeiro. Digo
View more...
Comments