next up previous
Seguinte: Sobre este documento ...

Threads, o que são?




Modelo de programação em que múltiplos fluxos de controle podem coexistir, permitindo a execução paralela de partes de um processo.




O modelo divide o processo em duas partes:

A segunda parte constitui a thread.



Dept de Ciência da Computação ©1998 1

Concorrência e Paralelismo






Dept de Ciência da Computação ©1998 2

Memória e Processo




\begin{figure}\epsffile{figuras/mproc.eps}\end{figure}



Dept de Ciência da Computação ©1998 3

Memória, Processo e duas Threads




\begin{figure}{\epsffile{figuras/mprth.eps}}
\end{figure}



Dept de Ciência da Computação ©1998 4

Threads $\times$ Processos






Dept de Ciência da Computação ©1998 5

Pthreads






Dept de Ciência da Computação ©1998 6

Exemplo

#include <pthread.h>
#include <stdio.h>

void do_one_thing (int  *); 
void do_another_thing (int *); void do_wrap_up (int, int);

int r1=0, r2=0;

void main() {
    pthread_t thread1, thread2; 

    pthread_create (&thread1, NULL, (void *) do_one_thing, (int *) &r1);
    pthread_create (&thread2, NULL, (void *) do_another_thing, (int *) &r2);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    do_wrap_up(r1, r2);
}

void  do_one_thing (int *pnum_times) {
    int i, j, x;
    for (i=0; i < 4; i++) {
        printf("doing one thing\n");
        for (j=0; j < 10000000; j++) x = x + i;
        (*pnum_times)++;  }
}

void do_another_thing (int *pnum_times) {
    int i, j, x;
    for (i=0; i < 4; i++) {
        printf("doing another thing\n");
        for (j=0; j < 10000000; j++) x = x + i;
        (*pnum_times)++;  }
}

void do_wrap_up (int one_times, int another_times) {
    int total;
    total = one_times + another_times;
    printf("wrap up: one thing %d, another %d, total %d\n",
            one_times, another_times, total);
}



Dept de Ciência da Computação ©1998 7

Rotinas




Rotinas que compõem o modelo de programação com threads.



Dept de Ciência da Computação ©1998 8

Criação de Threads






Dept de Ciência da Computação ©1998 9

Criação de threads cont.

int pthread_create(pthread_t *thread, pthread_attr_t *attr, 
              void * (*start_routine)(void *), void *arg);

Argumentos:

thread
Um ponteiro para um buffer para o qual a função retorna um valor que identifica a thread.
attr
Um ponteiro para uma estrutura que define várias características da thread. Um valor NULL indica que as características padrão serão aceitas.
start_routine
Um ponteiro para a rotina na qual a nova thread irá começar a executar.
arg
Um ponteiro para um parâmetro para ser passado para a thread.

Valores retornados:

zero:
Sucesso
EAGAIN:
Um limite do sistema foi atingido, por exemplo, threads demais.
EINVAL:
O valor de tattr não é válido.



Dept de Ciência da Computação ©1998 10

Atributos de threads




Os atributos são os seguintes:

Escopo:
indica se a thread de usuário será conectada a uma thread de sistema ou se compartilhará uma thread de sistema com outras do processo. O padrão é compartilhar.
Tipo:
indica se a thread é destacável ou ligável. O padrão é ligável.
Tamanho da pilha:
indica o tamanho da pilha da thread, medido em bytes.
Política de Escalonamento:
três políticas de escalonamento são definidos no padrão Pthreads; round-robin, fifo e o padrão do sistema.
Herança da política de escalonamento:
indica se a thread herdará ou não a política daquela que a disparou. O padrão é herdar.
Informações de escalonamento:
contém informações genéricas e que são dependentes da plataforma de implementação.



Dept de Ciência da Computação ©1998 11

Identificação de Threads




pthread_t pthread_self ( void );








int pthread_equal (pthread_t tid1, 
                     pthread_t tid2);



Dept de Ciência da Computação ©1998 12

Sincronização




pthread_join:
Esta função permite que uma thread suspenda sua execução até que outra termine.
Variáveis mutex:
Estas variáveis agem como cadeados mutuamente exclusivos, permitindo threads controlar acesso a dados compartilhados. Uma variável mutex permite que somente uma thread tenha acesso aos dados que ela controla.
Variáveis de condição:
Uma variável de condição permite nomear um evento em que threads tenham interesse. Um evento pode ser uma variável sendo escrita, uma coincidência de eventos, etc. A biblioteca pthreads permite que threads expressem interesse em uma condição ou sinalizem que uma condição esperada foi atingida.
pthread_once:
Esta é uma função especializada que permite que uma rotina de inicialização seja executada somente uma vez quando chamada por várias rotinas.



Dept de Ciência da Computação ©1998 13

Threads e seu término




Threads podem ser classificadas segundo o seu término em:

Ligáveis (joinable):
Este tipo ao final de sua execução aguarda até que uma outra faça um pedido pelo seu valor de retorno, liberando os recursos associados a ela e terminando somente neste momento.
Descoladas (detached):
Este tipo ao final de sua execução libera todos os recursos e termina.





Dept de Ciência da Computação ©1998 14

pthread_join

Uma thread ligável espera por uma chamado à função

int  pthread_join(pthread_t tid, void **status);

Argumentos:

tid
A thread que chamou pthread_join suspende a sua execução até que a thread identificada por tid termine, ou chamando pthread_exit ou sendo cancelada.
status
Um ponteiro para o local onde o valor de retorno da função tid é colocado. Este valor ou é o argumento dado para a função pthread_exit ou PTHREAD_CANCELLED se ela foi cancelada.

Valores retornados:

EINVAL:
tid não é uma thread válida.
ESRCH:
tid não é uma thread válida e descolada do processo atual.
EDEADLK:
tid especifica a thread que chamou.



Dept de Ciência da Computação ©1998 15

Descolando uma Thread




int  pthread_detach ( pthread_t tid );

Valores retornados:

EINVAL:
tid não é uma thread válida.
ESRCH:
tid não é uma thread válida e descolada do processo atual.



Dept de Ciência da Computação ©1998 16

Terminando uma thread




Uma thread pode terminar das seguintes maneiras:

O padrão é a thread permanecer executando até que outra se ligue com ela chamando pthread_join.

Um caso importante ocorre quando a thread principal temina com um exit. Neste caso todas as threads teminam.



Dept de Ciência da Computação ©1998 17

Terminando uma thread




Função usada para terminar uma thread.

int pthread_exit (void *status);



Dept de Ciência da Computação ©1998 18

Variáveis Mutex




Protegem um recurso compartilhado de condições de corrida.

Por exemplo, podem controlar a execução de pedaços de código que acessam dados. Estes pedaços são chamados de seções críticas.

Para usar variáveis em pthreads:

  1. Criar e iniciar um mutex para cada recurso compartilhado.
  2. Quando quiser acessar o recurso usar
    pthread_mutex_lock para reservá-lo; todas as outras threads serão obrigadas a esperar até que a que atualmente ocupa o recurso o espere.
  3. Quando a thread que reservou o recurso terminar com ele, deve liberá-lo com pthread_mutex_unlock.



Dept de Ciência da Computação ©1998 19

Inicializando um Mutex




Variáveis mutex são do tipo pthread_mutex_t e devem ser inicializadas ou estaticamente ou dinamicamente.

           int  pthread_mutex_init(pthread_mutex_t *mp, 
                          const pthread_mutex_attr_t *mattr);



Dept de Ciência da Computação ©1998 20

Bloqueando um Mutex




int  pthread_mutex_lock(pthread_mutex_t *mp);



Dept de Ciência da Computação ©1998 21

Desbloqueando um Mutex




int  pthread_mutex_unlock(pthread_mutex_t *mp);



Dept de Ciência da Computação ©1998 22

Exemplo com Mutexes

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>

void do_one_thing(int *); void do_another_thing(int *);
void do_wrap_up(int, int);

int r1 = 0, r2 = 0, r3 = 0;
pthread_mutex_t r3_mutex=PTHREAD_MUTEX_INITIALIZER;

extern int main(int argc, char **argv)
{
  pthread_t  thread1, thread2;

  if (argc > 1) r3 = atoi(argv[1]);
  if (pthread_create(&thread1, NULL,
       (void *) do_one_thing, (void *) &r1) != 0)
	perror("pthread_create"),exit(1); 
  if (pthread_create(&thread2, NULL, 
	 (void *) do_another_thing, (void *) &r2) != 0)
	perror("pthread_create"),exit(1); 
  if (pthread_join(thread1, NULL) != 0)
	perror("pthread_join"), exit(1);
  if (pthread_join(thread2, NULL) != 0)
	perror("pthread_join"), exit(1);
  do_wrap_up(r1, r2);
  return 0; 
}

void do_wrap_up(int one_times, int another_times)
{
  int total;

  total = one_times + another_times;
  printf("All done, one thing %d, another %d for a total of %d\n",
	one_times, another_times, total);
}


Dept de Ciência da Computação ©1998 23

Exemplo com Mutexes cont.

void do_one_thing(int *pnum_times)
{
  int i, j, x;
  
  pthread_mutex_lock(&r3_mutex);
  if(r3 > 0) {
	x = r3;
	r3--;
  } else {
	x = 1;
  } 
  pthread_mutex_unlock(&r3_mutex); 
  for (i = 0;  i < 4; i++) {
    printf("doing one thing\n"); 
    for (j = 0; j < 10000; j++) x = x + i;
    (*pnum_times)++;
  }
}

void do_another_thing(int *pnum_times)
{
  int i, j, x;
  
  pthread_mutex_lock(&r3_mutex);
  if(r3 > 0) {
        x = r3;
        r3--;
  } else {
        x = 1;
  }
  pthread_mutex_unlock(&r3_mutex);
  for (i = 0;  i < 4; i++) {
    printf("doing another \n"); 
    for (j = 0; j < 10000; j++) x = x + i;
    (*pnum_times)++;
  }
}



Dept de Ciência da Computação ©1998 24

Bloqueando com um Mutex Não Bloqueante




int  pthread_mutex_trylock(pthread_mutex_t *mp);



Dept de Ciência da Computação ©1998 25

Variáveis de Condição






Dept de Ciência da Computação ©1998 26

Bloqueando com variável de condição




int  pthread_cond_wait(pthread_cond_t *cv, 
                           pthread_mutex_t *mp);



Dept de Ciência da Computação ©1998 27

Desbloqueando uma thread




int  pthread_cond_signal(pthread_cond_t *cv);



Dept de Ciência da Computação ©1998 28

Estrutura básica para variáveis de condição




Já que a condição pode mudar antes que a thread acordada retorne de pthread_cond_wait(), esta deve ser testada novamente antes que a variável mutex seja adquirida.

A estrutura abaixo é recomendada para uso com variável de condição.

      pthread_mutex_lock();
      while (condition_falsa) 
            pthread_cond_wait();
      pthread_mutex_unlock();



Dept de Ciência da Computação ©1998 29

Exemplo com variáveis de condição

#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS  3
#define TCOUNT 10
#define COUNT_THRES 12

int     count = 0;   int  thread_ids[3] = {0,1,2};
pthread_mutex_t count_lock=PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t count_hit_threshold=PTHREAD_COND_INITIALIZER; 

void *inc_count(void *idp)
{
  int i=0, save_state, save_type; int *my_id = idp;

  for (i=0; i<TCOUNT; i++) {
    pthread_mutex_lock(&count_lock);
    count++;
    printf("inc_counter(): thread %d, count = %d, unlocking mutex\n", 
	   *my_id, count);
    if (count == COUNT_THRES) {
      printf("inc_count(): Thread %d, count %d\n", *my_id, count);
      pthread_cond_signal(&count_hit_threshold);
    }
    pthread_mutex_unlock(&count_lock);
  }
  return(NULL);
}

void *watch_count(void *idp)
{
  int i=0, save_state, save_type; int *my_id = idp;

  printf("watch_count(): thread %d\n", *my_id);
  pthread_mutex_lock(&count_lock);
  while (count < COUNT_THRES) {
    pthread_cond_wait(&count_hit_threshold, &count_lock);
    printf("watch_count(): thread %d, count %d\n", *my_id, count);
  }
  pthread_mutex_unlock(&count_lock);
  return(NULL);
}



Dept de Ciência da Computação ©1998 30

Exemplo com variáveis de condição cont.




extern int main(void)
{
  int i;  pthread_t threads[3];

  pthread_create(&threads[0], NULL, inc_count, (void *)&thread_ids[0]);
  pthread_create(&threads[1], NULL, inc_count, (void *)&thread_ids[1]);
  pthread_create(&threads[2], NULL, watch_count, (void *)&thread_ids[2]);
  for (i = 0; i < NUM_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }
  return 0;
}



Dept de Ciência da Computação ©1998 31

Cancelando uma thread




Função usada para cancelar uma thread.

int pthread_cancel (pthread_t *tid);



Dept de Ciência da Computação ©1998 32

Cancelando uma thread cont.




Fatores importantes quando cancelando uma thread.

Estado de Cancelabilidade:
capacidade da thread de terminar quando outra pede o seu término.
Tipo da Cancelabilidade:
gráu em que uma thread persiste após ter recebido o pedido de cancelamento.
Pilha de limpeza:
Capacidade da thread entrar em um processo de limpeza como parte de seu término.



Dept de Ciência da Computação ©1998 33

Cuidados com o Cancelamento






Dept de Ciência da Computação ©1998 34

Cancelabilidade





Estado de Cancelabilidade Tipo da Cancelabilidade Descrição
PTHREAD_CANCEL_ Ignorado Inibido.
EISABLE   A thread não pode ser cancelada.
    Chamadas a pthread_cancel
    não tem efeito.
PTHREAD_CANCEL_ PTHREAD_CANCEL_ Cancelamento ocorre imediatamente.
ENABLE ASYNCHRONOUS  
PTHREAD_CANCEL_ PTHREAD_CANCEL_ Cancelamento adiado (default).
ENABLE DEFERRED O cancelamento ocorre quando a thread
    entra em um ponto de cancelamento.






Dept de Ciência da Computação ©1998 35

Pontos de Cancelamento




Quando o cancelamento esta liberado
(PTHREAD_CANCEL_ENABLED) e o seu tipo é
(PTHREAD_CANCEL_ASYNCHRONOUS) ocorre um tempo entre o pedido e o efetivo cancelamento.

Há dois tipos de pontos de cancelamento:

Automáticos:
pthread_cond_wait,
pthread_cond_timedwait
e pthread_join.
Estes são pontos de cancelamento padrão. Se estas funções não são chamadas pode ocorrer da função nunca ser cancelada.
Definidos pelos usuários:
A chamada
pthread_testcancel força um pedido de cancelamento que está pendente ser atendido. Caso não haja pedidos nada ocorre.



Dept de Ciência da Computação ©1998 36

Testa Cancelamento




Função usada para testar se há pedido de cancelamento.

void pthread_testcancel (void );



Dept de Ciência da Computação ©1998 37

Estado de Cancelamento




Função usada para liberar ou inibir pedidos de cancelamento.

int pthread_setcancelstate (int state, int *oldstate );




int ret, oldstate;

ret = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &oldstate);
ret = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);



Dept de Ciência da Computação ©1998 38

Tipo de Cancelamento




Função usada para estabelecer o tipo de cancelamento para assíncrono ou deferido.

int pthread_setcanceltype (int type, int *oldtype );




int ret, oldtype;

ret = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &oldtype);
ret = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);



Dept de Ciência da Computação ©1998 39

Exemplos de Cancelamento

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>

#define NUM_THREADS  3
#define MESSAGE_MAX_LEN 80

int count=NUM_THREADS;    /* number of threads active */
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t init_done=PTHREAD_COND_INITIALIZER; 
int id_arg[3] = {0,1,2};

void print_count(char *messagep, int id, int i) 
{
  int last_type,tmp_type;

  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type);
  switch(id) {
  case 0:
    printf("%s %4d\n", messagep, i);
    break;
  case 1:
    printf("%s \t%4d\n", messagep, i);
    break;
  case 2:
    printf("%s \t\t%4d\n", messagep, i);
    break;
  }
  pthread_setcanceltype(last_type, &tmp_type);
}



Dept de Ciência da Computação ©1998 40

Exemplos de Cancelamento cont. 1

void *bullet_proof(void *id_p)
{
  int i=0, last_state; int *my_id = id_p;
  char *messagep;

  messagep = (char *)malloc(MESSAGE_MAX_LEN);
  sprintf(messagep, "Bullet Proof, thread #%d: ", *my_id);

  printf("%s\tI'm Alive, setting general cancellation OFF\n", messagep);
  /* We turn off general cancelability here ... */
  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &last_state);
  
  pthread_mutex_lock(&lock);
  {
    printf("\n%s signaling main that my init is done\n", messagep);
    count -= 1;
    /* signal to program that entering loop */
    pthread_cond_signal(&init_done);
    pthread_mutex_unlock(&lock);
  }

  /* loop forever until picked off with a cancel */
  for(;;i++) {
    if (i%100000 == 0) 
      print_count(messagep, *my_id, i); 
    if (i%1000000 == 0) {
      printf("\n%s This is the thread that never ends... #%d\n", 
             messagep, i);
    }
  }
  /* Never get this far   */
  return(NULL);
}



Dept de Ciência da Computação ©1998 41

Exemplos de Cancelamento cont. 2

void *ask_for_it(void *id_p)
{
  int i=0, last_state, last_type; int *my_id = id_p;
  char *messagep;

  messagep = (char *)malloc(MESSAGE_MAX_LEN);
  sprintf(messagep, "Ask For It, thread #%d: ", *my_id);

  /* We can turn on general cancelability here. Disable async cancellation */
  printf("%s\tI'm Alive, setting deferred cancellation ON\n", messagep);
  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type);
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);

  pthread_mutex_lock(&lock);
  {
    printf("\n%s signaling main that my init is done\n", messagep);
    count -= 1;
    /* signal to program that entering loop */
    pthread_cond_signal(&init_done);
    pthread_mutex_unlock(&lock);
  }

  /* loop forever until picked off with a cancel */
  for(;;i++) {
    if (i%100000 == 0)
      print_count(messagep, *my_id, i);
    if (i%1000000 == 0) {
      printf("\n%s\tLook, I'll tell you when you can cancel me.\n",messagep,i);
    }
    pthread_testcancel();
  }
  /* never get this far */
  return(NULL);
}



Dept de Ciência da Computação ©1998 42

Exemplos de Cancelamento cont. 3

void *sitting_duck(void *id_p)
{
  int i=0, last_state, last_type, last_tmp;
  int *my_id = id_p;
  char *messagep;

  messagep = (char *)malloc(MESSAGE_MAX_LEN);
  sprintf(messagep, "Sitting Duck, thread #%d: ", *my_id);

  pthread_mutex_lock(&lock);
  {
    printf("\n%s signaling main that my init is done\n", messagep);
    count -= 1;
    /* signal to program that entering loop */
    pthread_cond_signal(&init_done);
    pthread_mutex_unlock(&lock);
  }

  /* Now, we're safe to turn on async cancellability */
  printf("%s\tI'm Alive, setting async cancellation ON\n", messagep);
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
 
  /* loop forever until picked off with a cancel */
  for(;;i++) {
    if (i%100000 == 0) 
      print_count(messagep, *my_id, i++);
    if (i%1000000 == 0) {
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_tmp);
      printf("\n%s\tHum, nobody here but us chickens. %d\n", messagep,i);
      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_tmp);
    }
  }
  /* never get this far */
  return(NULL);
}



Dept de Ciência da Computação ©1998 43

Exemplos de Cancelamento cont. 4

extern int main(void)
{
  int       i;
  void *statusp;
  pthread_t threads[NUM_THREADS];

  /* spawn the threads */
  pthread_create(&(threads[0]), NULL, ask_for_it, (void *) &(id_arg[0]));
  pthread_create(&(threads[1]), NULL, sitting_duck, (void *) &(id_arg[1]));
  pthread_create(&(threads[2]), NULL, bullet_proof, (void *) &(id_arg[2]));
  printf("main(): %d threads created\n", NUM_THREADS);
  
  pthread_mutex_lock(&lock);
  /* wait until all threads have entered loops */
  while (count != 0) 
      pthread_cond_wait(&init_done, &lock);
  pthread_mutex_unlock(&lock);
  printf("main(): all threads have signaled that ready\n");

  /* cancel each thread */
  for (i=0; i<NUM_THREADS; i++) 
    pthread_cancel(threads[i]);
   
  /* wait until all threads have finished */
  for (i=0; i<NUM_THREADS; i++) {
    pthread_join(threads[i], &statusp);
    if (statusp == PTHREAD_CANCELED) 
      printf("main(): joined to thread %d, statusp=PTHREAD_CANCELED\n",i);
    else 
      printf("main(): joined to thread %d\n",i);
  }
  printf("main()\t\tall %d threads have finished. \n", NUM_THREADS);
  return 0;
}



Dept de Ciência da Computação ©1998 44

Pilhas de Limpeza






Dept de Ciência da Computação ©1998 45

Gerenciando as Pilhas de Limpeza




void pthread_cleanup_push ( 
       void (*rotina) (void *), void *arg );








void pthread_cleanup_pop (int execute);



Dept de Ciência da Computação ©1998 46

Exemplos de Pilhas de Limpeza

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define NUM_LINHAS 10 
#define NUM_THREADS 2 
#define NUM_MAX 100.0 
#define MESSAGE_MAX_LEN 80

int vetor[NUM_LINHAS];  int aponta_linha= NUM_LINHAS-1;
pthread_mutex_t aponta_linha_lock= PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t acabaram_linhas_cond= PTHREAD_COND_INITIALIZER;

main() {
    int i,j, maximo;
    pthread_t threads_id[NUM_THREADS];
    void *statusp;

    for(i= 0;i<NUM_THREADS;i++){
        if(pthread_create(&threads_id[i],NULL, escreve_vetor, NULL) != 0){
            perror("pthread_create");
            exit(1);
        }
    }
    pthread_mutex_lock(&aponta_linha_lock);
    while(aponta_linha>=0)
        pthread_cond_wait(&acabaram_linhas_cond,&aponta_linha_lock);
    pthread_mutex_unlock(&aponta_linha_lock);

    for (i=0; i<NUM_THREADS; i++){
        printf("Cancelando a thread %d\n", threads_id[i]);
        pthread_cancel(threads_id[i]);
    }
    /* wait until all threads have finished */
    for (i=0; i<NUM_THREADS; i++) {
        pthread_join(threads_id[i], &statusp);
        if (statusp == PTHREAD_CANCELED) {
              printf("main(): joined to thread %d, statusp=PTHREAD_CANCELED\n",i);
        } else 
      printf("main(): joined to thread %d\n",i);
    }
}



Dept de Ciência da Computação ©1998 47

Exemplos de Pilhas de Limpeza cont.

void limpando (char *messagep) {
  printf("\n\n%s rotina limpando() limpando 0x%x\n\n", messagep, messagep);
  free(messagep);
}

void *escreve_vetor( ){
    int i=0, linha, last_type, last_state;
    char *messagep;
    pthread_t id;

    id = pthread_self();
    srand(time(NULL));
    messagep = (char *)malloc(MESSAGE_MAX_LEN);
    sprintf(messagep, "Escreve Vetor, thread #%d: ", id);
    pthread_cleanup_push( (void *)limpando, (void *)messagep );
    while(1){
        pthread_mutex_lock(&aponta_linha_lock);
        linha= aponta_linha;
        aponta_linha--;
        printf("escreve_vetor(): tid=%d, Achei apontador de linhas com %d\n",
            id, linha);
        pthread_mutex_unlock(&aponta_linha_lock);
        if(linha<0){
            pthread_cond_signal(&acabaram_linhas_cond);
            break;
        } else 
            vetor[linha]=1+(int)(NUM_MAX*rand()/(RAND_MAX+1.0));
        for (i=0; i<100000; i++) ;
    }
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
    /* loop forever until picked off with a cancel */
      for(;;i++) {
        if (i%10000 == 0) {
              pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type);
              printf("\n%s\tEpa, esperando ser cancelado. %d\n", messagep,i);
              pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
        }
      }
  /* This pop is required, every push must have a pop in the same block. */
      pthread_cleanup_pop(0);
      return(NULL);
}



Dept de Ciência da Computação ©1998 48

pthread_once()

int pthread_once(pthread_once_t *once_control,  
                        void (*init_routine)(void ));





Dept de Ciência da Computação ©1998 49

Keys - Chaves






Dept de Ciência da Computação ©1998 50

Aplicações de Chaves






Dept de Ciência da Computação ©1998 51

Características






Dept de Ciência da Computação ©1998 52

Criando Chaves




int pthread_key_create (pthread_key_t *key,  
                        void (*destructor)(void *));





Dept de Ciência da Computação ©1998 53

Associando Chaves com Dados




int pthread_setspecific (pthread_key_t *key,  
                                    void *value);





Dept de Ciência da Computação ©1998 54

Chaves e a Memória




\begin{figure}\epsffile{figuras/chaves.eps}\end{figure}



Dept de Ciência da Computação ©1998 55

Obtendo o Dado




int pthread_getspecific (pthread_key_t *key);




Dept de Ciência da Computação ©1998 56

Apagando a Chave




int pthread_key_delete (pthread_key_t *key);





Dept de Ciência da Computação ©1998 57

Usando Chaves




#include <pthread.h>

pthread_key_t key;
int ret;
void *value;


/* Criando chaves sem destruidores */
ret = pthread_key_create (&key, NULL);

/* Criando chaves com destruidores */
ret = pthread_key_create (&key, destruidor);

/* Sendo mais especifico */
ret = pthread_setspecific (key, value);

/* Acabando com a festa */
ret = pthread_key_delete (&key);


/* Agora dentro de uma thread *;

/* Usando a chave */
void *value1;
value1 = pthread_getspecific (key);


Dept de Ciência da Computação ©1998 58

Exemplo de Chaves

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#define NUM_THREADS  3
pthread_key_t     saved_time_key;

void save_the_time(void *arg) {
	struct timeval *tv;
  	int *my_id=(int *)arg;

    tv = (struct timeval *) malloc (sizeof(struct timeval));
    gettimeofday(tv, (struct timezone*)0);
  	printf("save_the_time thread %d: \t\t%ld %ld\n",
                      *my_id, tv->tv_sec, tv->tv_usec);
  	pthread_setspecific(saved_time_key, (void *) tv); }

void what_time_did_i_save(void *arg) {
  int *my_id=(int *)arg, rtn;
  struct timeval *timep;

  printf("thread_routine %d\n", *my_id);
  timep = pthread_getspecific(saved_time_key);
  printf("what_time_did_i_save thread %d: \t%ld %ld\n",
                  *my_id, timep->tv_sec, timep->tv_usec); }  

void *thread_routine(void *arg) {
  int *my_id=(int *)arg;

  printf("thread_routine %d\n", *my_id);
  save_the_time(arg);
  sleep(2);
  what_time_did_i_save(arg);
  return(NULL); }


Dept de Ciência da Computação ©1998 59

Exemplo de Chaves cont.







void free_time(void *arg ) {
  struct timeval *timep=(struct timeval *)arg; 
  printf("free_time:\n");
  free(timep);
}

extern int main(void) {
    int       i, *id_arg;
    pthread_t threads[NUM_THREADS];
    id_arg = (int *)malloc(NUM_THREADS*sizeof(int));

    printf("main : initializing the key\n");
    pthread_key_create(&saved_time_key, free_time);
    printf("main : spawing the threads\n");
    for (i = 0; i < NUM_THREADS; i++) {
    	id_arg[i] = i;
    	pthread_create(&(threads[i]), NULL, thread_routine,
    		       (void *) &(id_arg[i]));
    }

    for (i = 0; i < NUM_THREADS; i++) {
      pthread_join(threads[i], NULL);
       printf("main : thread %d has finished. \n", i);
    }
    printf("main : goodbye\n");
    return 0;
}


Dept de Ciência da Computação ©1998 60




next up previous
Seguinte: Sobre este documento ...
Adriano Joaquim de Oliveira Cruz 2003-06-23