VinBR

AEDs III 18/04/2011

Mar 6th, 2012
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.40 KB | None | 0 0
  1. Vamos falar sobre uma biblioteca de paralelismo,
  2. de nome pthread.
  3.  
  4. Nos primeiros softwares não se pensava em permitir o compartilhamento de memória entre dois processos
  5. pois casos como esse normalmente se enquadravam como erros e deviam ser evitados.
  6.  
  7. Algum tempo depois disso com o aumento da capacidade de processamento dos processadores e do surgimento dos
  8. computadores multi-processados, criou-se a idéia dos "processos leves" que poderiam representar uma fração
  9. de um processo maior, e pela primeira vez realizar processamentos de maneira paralela.
  10.  
  11. Os processos leves, também chamados de "threads" ou em português "seguimentos" passaram então
  12. a compor programas que agora possuem vários processos simuntâneos, e todos compartilhando o mesmo campo de memória,
  13. e trabalhando um mesmo problema.
  14.  
  15. Nessa aula de hoje estudaremos um tipo especifico de programação com uso de threads,
  16. que serão as pthreads que é uma biblioteca em linguagem C para uso nos compiladores para linux.
  17.  
  18. Vantagens do uso de pThreads:
  19. - portabilidade de software // Funcionam em várias arquiteturas
  20. - esconder latência
  21. - e fácil de usar
  22. // Obs eu não consegui anotar todas as vantagens e nem sei se as que anotei estão 100% corretas.
  23. // Mas deixarei aí de qualquer forma.
  24.  
  25. Abaixo especificarei detalhes técnicos do uso de pthreads em código C
  26. que o professor nós sugeriu práticar antes do próximo trabalho prático.
  27.  
  28. A biblioteca a ser inclusa para seu uso:
  29. #include <pthread.h>
  30.  
  31. A função construtora que lança uma thread para ser processada:
  32. int pthread_create
  33. (
  34. pthread_t* thread_handle, // Identificador retornado pelo criador de threads.
  35. attr, // Parâmetro de configuração da thread -> O uso dessa entrada ainda não nós será explicado.
  36. ponteiro para funcao, // Toda thread deve possuir uma função que reja seu funcionamento (obviamente).
  37. parametro em forma void* // Essa função estará prepara para receber um e somente um argumento, que
  38. // pode ser estruturado em forma de um ponteiro para struct para agrupar mais parâmetros.
  39. );
  40.  
  41. A função acima é a função básica, e com ela já é possível a criação de uma thread, e naturalmente uma vez que
  42. a função descritiva da thread termine a thread também será encerrada.
  43. É importante notar que o meio pelo qual uma thread pode retornar uma saída não é como as demais funções,
  44. os únicos retornos possíveis são através do uso de ponteiros e arranjos passados como parâmetros dentro do struct de entrada.
  45.  
  46. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  47.  
  48. Uma vez que uma thread tenha se iniciado, pode ser útil saber quando ela vai terminar,
  49. muitas vezes parte do processamento só pode ocorrer uma vez que uma thread encerre seu funcionamento.
  50. Para isso existe a função:
  51. int pthread_join
  52. (
  53. pthread_t thread, // Id da thread que voce quer se juntar que é retornado pela função construtora da mesma.
  54. );
  55.  
  56. Uma vez chamada essa função o código só seguirá em frente quando a thread especificada for encerrada.
  57. Permitindo a sincronização de dois ou mais processos.
  58.  
  59. Um meio para encerrar uma thread que esteja em funcionamento é utilizar a função abaixo:
  60. int pthread_exit(0)
  61.  
  62. Ao invés de simplismente retornar a função. Imagino que este metodo seja mais correto,
  63. mas ainda não sei bem porquê.
  64.  
  65. Nota importante do professor:
  66. Não use ponteiros recebidos por parametro em uma thread com frequencia!
  67. a cada acesso a um ponteiro deste você estará acessando a memória de outro processador
  68. gerando um grande overhead desnecessáriamente. Tenha preferencia por cópiar os dados necessários
  69. para variaveis locais de fácil acesso.
  70.  
  71. CONCEITO:
  72. Condição de corrida é a caracteristica intrinsica das threads que às impede de editar uma mesma variável
  73. de maneira previsível. Ou seja, se há duas threads acessando a mesma variável não há como
  74. saber qual delas escreverá nesta variável por último, o que pode gerar confusão
  75. e portanto deve ser sempre tratado para evitar erros.
  76.  
  77. Uma solução para este tipo de problema é a "travagem" dos acessos a uma variável, no intuito de garantir
  78. o monopólio de seu acesso a uma única thread.
  79. Essa solução já é facilitada pelo uso de uma conjunto de funções chamadas mutex
  80. cujas principais seguem abaixo:
  81.  
  82. pthread_mutex_init( variavel global) // inicia uma variável.
  83. pthread_mutex_lock( var global ) // Essa função pode ser usada por uma thread para travar uma variável em seu monopólio.
  84. pthread_mutex_unlock( var global ) // Destrava a variavel permitindo então o acesso à ela por outra thread.
  85. // Também existem funções para se saber se uma váriavel está travada ou não antes de acessa-la, mas falaremos disso mais abaixo.
  86.  
  87. Nota do professor:
  88. Se voce implementar isso na forma de um verificador constante de lock voce estará abusando do processador e disperdiçando
  89. tempo de processamento, portanto se possível encontre uma tarefa alternativa para ser realizada sempre que uma thread
  90. detectar que a variável que ela deseja acessar está travada.
  91. O nome desse processo de repetição é "biziwaking", apesar de só conhecer este nome de ouvido.
  92.  
  93. Existem 3 tipos de mutex o normal o recursivo e o error check
  94. esses 3 tem 3 jeitos diferentes de lidar com isso
  95. e um problema serio eh o risco de uma thread travar a si mesma, bloqueando a variavel para sempre.
  96.  
  97. A função "trylock" abaixo é responsável pela verificação da disponibilidade de uma váriavel,
  98. e se essa variável se encontrar livre ela é então travada garantindo o acesso à variável.
  99. int pthread_mutex_trylock(pthread_mutex_t);
  100.  
  101. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  102.  
  103. Um outro meio de lidar com a sincronização de threads é utilizando uma variável de condição.
  104. Uma variável de condição, é usada como uma flag, que destrava o funcionamento de uma thread
  105. no momento em que ela for ativada, ou no caso especifico que vou mostrar abaixo
  106. no momento em que ela for modificada:
  107. Para esse propósito pode-se usar a função pthread_cond_wait()
  108. pthread_cond_wait( variavel global )
  109. Uma vez que esta função for chamada ela só retorna quando o valor da variavel global em questão for editado.
  110. A ativação deste flag portanto é uma variação qualquer daquela variavel, como por exemplo um incremento.
  111.  
  112. CONCEITO:
  113. Barreira, eh uma estrategia de sincronizacao coletiva que eh quando voce espera todas as threads terminarem uma tarefa para continuar.
  114. A função pthread_cond_wait(VG) pode ser usada na criação de uma barreira. Use por exemplo uma variável X=0 para ser incrementada
  115. sempre que uma thread chegar no ponto de sincronização. Quando a última thread chegar, ela verá que ela é a ultima a terminar
  116. pelo valor na variavel incrementada, e poderá então alterar o valor da variável "VG" da função pthread_cond_wait() e liberar todas as outras para continuar o processamento.
  117.  
  118. CONCEITO:
  119. Deadlock é um erro que ocorre quando duas threads impedem travam o funcionamento uma da outra de forma que
  120. enquanto nem uma das duas for destravada, ambas continuarão presas para sempre. Sabotando o funcionamento do programa.
  121. Um meio comum disso acontecer é quando dadas duas threads t1 e t2 e duas variáveis a e b que são sempre usadas juntas,
  122. a thread 1 da um trylock em A e simuntaneamente a thread 2 da um trylock em B, em seguida ambas as threads entram em loop aguardando
  123. que um trylock em B e A respectivamente às threads 1 e 2 retorne positivo.
  124. Ou seja, cada uma fica sem fazer nada esperando que a outra libere o lock da variável, e ficam nisso eternamente.
  125.  
  126. Um macete para evitar isso é sempre garantir que os locks sobre um grupo de variáveis são acessados sempre na mesma ordem
  127. por todas as threads que às usam.
  128.  
  129. // A aula de hoje foi isso,
  130. // Foi um pouco indigesta devido a grande quantidade de informações, o ideal é estudar separadamente cada uma das funções
  131. // citadas, e práticar o uso delas em um código C. Realmente não é um "para casa" fácil =/.
  132. // Também não garanto que as informações contidas nessa nota de aula especifica sejam confiáveis, eu me lembro que esta aula
  133. // aconteceu muito rápido e não fui capaz de copiar tudo. Por isso podem haver alguns erros no que escrevi.
  134. // Boa sorte nos estudos, também vou precisar.
Advertisement
Add Comment
Please, Sign In to add comment