Escolar Documentos
Profissional Documentos
Cultura Documentos
Barramento
Cache
Processadores
Mdulos de memria
Fortran F
Extenso a Fortran para programao por paralelismo de dados Extenso a Modula 2 Extenso ao Pascal
FORK FORK
Processos UNIX
A chamada do UNIX fork() cria um novo processo, denominado processo filho O processo filho uma cpia exata do processo que chama a rotina fork(), sendo a nica diferena um identificador de processo diferente Esse processo possui uma cpia das variveis do processo pai inicialmente com os mesmos valores do pai O processo filho inicia a execuo no ponto da chamada da rotina Caso a rotina seja executada com sucesso, o valor 0 retornado ao processo filho e o identificador do processo filho retornado ao processo pai
Processos UNIX
Os processos so ligados novamente atravs das chamadas ao sistema:
wait(status): atrasa a execuo do chamador at receber um sinal ou um dos seus processos filhos terminar ou parar exit(status): termina o processo
Threads
Heap Cdigo
Processos: programas completamente separados com suas prprias variveis, pilha e alocao de memria
IP
Pilha
Pilha IP
Rotinas de interrupo
Arquivos
Pthreads
Interface portvel do sistema operacional, POSIX, IEEE Programa principal
thread1
proc1(&arg); { pthread_create(&thread1, NULL, proc1, &arg); return(&status); } pthread_join(thread1, NULL, &status);
Threads desunidas
Uma thread no precisa saber do trmino de uma outra por ela criada, ento no executa-se a operao de unio Programa principal
pthread_create();
Thread
pthread_create();
Thread
pthread_create();
Trmino
Possvel ordem de execuo no tempo: Instruo 1.1 Instruo 1.2 Instruo 2.1 Instruo 1.3 Instruo 2.2 Instruo 2.3
Otimizaes do compilador/processador
O compilador ou processador pode reordenar as instrues para tentar otimizar a execuo Exemplo:
As instrues abaixo a = b + 5; x = y + 4; podem ser executadas em ordem contrria: x = y + 4; a = b + 5; e o programa continua logicamente correto
tempo
Escrever
+1
Processo 1
Processo 2
Seo crtica
Devem existir mecanismos para assegurar que somente um processo possa acessar um determinado recurso durante um certo tempo Estabelecem-se sesses de cdigo que envolvem o recurso, denominadas sees crticas, e organiza-se o acesso a elas de tal modo que somente uma delas pode ser executada por um processo de cada vez Um processo impede que outros processos acessem as sees crticas que possui um determinado recurso compartilhado quando ele estiver acessando Quando um processo finaliza a execuo da seo crtica, outro processo pode execut-la Mecanismo conhecido como excluso mtua
Lock
Mecanismo mais simples de assegurar excluso mtua para acesso a sees crticas O lock uma varivel de 1 bit que possui o valor 1 quando existe algum processo na seo crtica e 0 quando nenhum processo est na seo crtica Um processo que chega a uma porta da seo crtica e a acha aberta pode entrar, trancando-a para prevenir que nenhum outro processo entre Assim que o processo finaliza a execuo da seo crtica, ele destranca a porta e sai
Spin lock
while (lock == 1) do_nothing; lock = 1; . seo crtica . lock=0; Processo 1 while (lock == 1) do _nothing; lock =1; seo crtica lock=0; lock = 1; seo crtica Processo 2 while (lock == 1) do_nothing;
lock = 0;
Se uma thread chega em uma rotina de trancamento de uma varivel mutex e a encontra trancada, ela espera at que seja destrancada Se mais de uma thread est esperando o destrancamento, o sistema escolhe aquela que poder prosseguir Somente a thread que tranca uma varivel pode destranc-la
Deadlock
Pode ocorrer com dois processos quando um deles precisa de um recurso que est com outro e esse precisa de um recurso que est com o primeiro
R1
R2
Recurso
P1
P2
Processo
Deadlock
Pode ocorrer em modo circular com vrios processos possuindo um recurso necessrio a um outro
R1
R2
Rn-1
Rn
P1
P2
Pn-1
Pn
Semforos
Um semforo s um inteiro positivo (incluindo o 0) operado por duas operaes denominadas P e V Operao P(s)
espera at que s seja maior que 0, a decrementa de 1 e permite que o processo continue a sua execuo
Operao V(s)
incrementa s de 1 para liberar algum processo que esteja esperando
Mecanismo de espera implcito nas operaes Os processo atrasados por P(s) so mantidos parados at serem liberados por uma operao V(s) sobre o mesmo semforo
Semforo geral
Pode ter qualquer valor positivo Pode fornecer, por exemplo, um modo de registrar o nmero de unidades do recurso disponveis ou no disponveis e pode ser utilizada para resolver problemas de consumidor/produtor Rotinas de semforo existem para processos UNIX No existem para Pthreads, somente para extenso de tempo real
Monitor
Um conjunto de procedimentos que fornecem o nico mtodo de acessar um recurso compartilhado Os dados e operaes que podem ser executadas sobre os dados so encapsulados em uma estrutura A leitura e escrita de dados s podem ser feitas utilizando-se procedimentos do monitor, e somente um processo pode utilizar um procedimento de monitor em qualquer instante Um procedimento de monitor pode ser implementado utilizando-se semforos
monitor_proc1() { P(monitor_semaphore); . Corpo do monitor . V(monitor_semaphore); return; }
Variveis de condio
Freqentemente, uma seo crtica deve ser executada caso exista uma condio especfica, por exemplo, o valor de uma varivel chegou a um determinado valor Utilizando-se locks, a varivel global tem que ser freqentemente examinada dentro da seo crtica Consome tempo de CPU e podem no funcionar direito Utilizam-se variveis de condio
A rotina wait() libera o semforo ou lock e pode ser utilizada para permitir que outro processo altere a condio Quando o processo que chamou a rotina wait() liberado para seguir a execuo, o semforo ou lock trancado novamente
Construes forall
Para iniciar execues de mltiplos processos conjuntamente:
forall (i = 0; i , n; i++) { S1; S2; . Sn; }
Geram-se n processos cada um executando as instrues que formam o corpo do loop for, S1, S2, ..., Sn e cada processo utiliza um valor diferente para i Exemplo para colocar o valor 0 em a[0], a[1], a[2], a[3], a[4] concorrentemente:
forall (i = 0; i < 5; i++) a[i] = 0;
Anlise de dependncia
Identificao dos processos que podem ser executados em conjunto No cdigo abaixo, a instruo do corpo do forall independente de todas as outras e todas podem ser executadas de forma independente No entanto, pode a identificao de dependncia pode no ser to bvia, necessitando-se de algoritmos de reconhecimento de dependncia para compiladores paralelizadores
Condies de Bernstein
Conjunto de condies suficientes para determinar se dois processos podem ser executados simultaneamente Sejam Ii o conjunto de localizaes de memria lidas por um processo Pi e Oj o conjunto de localizaes alteradas pelo processo Pj Trs condies suficientes para que dois processos P1 e P2 sejam executados concorrentemente
I1 O2 = I2 O1 = O1 O2 =
Temos:
I1 = (x,y) I2 = (x,z) O1 = (a) O1 = (b)
Existem as trs condies suficientes para que dois processos P1 e P2 sejam executados concorrentemente
I1 O2 = I2 O1 = O1 O2 =
Compartilhamento falso
Partes diferentes de um bloco de dados utilizadas por processadores diferentes Se um processador escrever em uma parte do bloco, a cpia de todo bloco deve ser invalidada ou atualizada nas caches dos outros processadores
Memria principal
Bloco
Tag de endereo
7 6 5 4 3 2 1 0
Cache
Bloco na cache Processador 1
Cache
Processador 2
Exemplos de programas
Somar os elementos de um array, a[1000]
int sum, a[1000] sum = 0; for (i = 0; i < 1000; i++) sum = sum +a[i];
Cada processo soma o seu resultado (sum1 ou sum2) a uma varivel compartilhada sum que acumula o resultado e deve ser ter seu acesso protegido Estrutura de dados utilizada
sum Array a[]
addr
#define array_size 1000 extern char *shmat() void P(int *s); void V(int *s); int main() { int shmid, s, pid; cahr *shm; int *a, *addr, *sum; int partial_sum; int i; init init_sem_value =1 ; s = semget(IPC_PRIVATE, 1, (0600 | IPC_CREAT)); if (s == -1) { perror(semget); exit(1); } if semctl(s, 0, SETVAL, init_sem_value) < 0) { perror(semctl); exit(1); } shmid = shmget(IPC_PRIVATE, (array_size*sizeof(int)+1), IPCCREAT|0600); if (shmid == -1) { perror(shmget); exit (1); } shm = shmat(shmid, NULL, 0); if (shm == (char*)-1) { perror(shmat); exit(1); }
addr = (int *) shm; sum = addr; addr++; a = addr; *sum = 0; for (i = 0; i < array_size; i++) *(a+i) = i+1; pid = fork(); if (pid ==0) { partial_sum=0; for (i=0; i<array_size; i=i+2) partial_sum+=*(a+i); else { partial_sum=0; for (i=1; i<array_size; i=i+2) partial_sum+=*(a+i); } P(&s); *sum+=partial_sum; V(&s); printf(\n pid do processo = %d, soma parcial = %d \n, pid, partial_sum); if (pid == 0) exit (0); else wait(0); printf(A soma total %d \n, *sum); if (semctl(s, 0, IPC_RMID,1) == -1) { perror(semctl); exit(1); } if (shmctl(shmid, IPC_RMID, NULL) == -1) { perror(shmctl); exit(1); } }
void P(int *s) { struct sembuf sembuffer, *sops; sops = &sembuffer; sops->sem_num=0; sops->sem_op=-1; sops->sem_flg=0; if (semop(*s, sops, 1) < 0) { perror (semop); exit (1); } return; } void V(int *s) { struct sembuf sembuffer, *sops; sops = &sembuffer; sops->sem_num=0; sops->sem_op=1; sops->sem_flg=0; if (semop(*s, sops, 1) < 0) { perror (semop); exit (1); } return; }
addr
#define array_size 1000; #define no_threads 10; int a[array_size]; int global_index = 0; int sum = 0; pthread_mutex_t mutex1; void *slave (void *ignored) { int local_index, partial_sum =0; do { pthread_mutex_lock&(mutex1); local_index = global_index; global_index++; pthread_mutex_unlock(&mutex1); if (local_index < array_size) partial_sum += *(a+local_index); } while (local_index < array_size); pthread_mutex_lock(mutex1); sum+=partial_sum; pthread_mutex_unlcok(&mutex1); return(); }
main() { int i; pthread_t thread[no_threads]; pthread_mutex_init(&mutex1, NULL); for (i = 0; i < array_size; i++) a[i] = i+1; for (i = 0; i < no_threads; i++) if (pthread_create(&thread[i], NULL, slave, NULL) != 0) { perror(Pthread_create falhou); exit(1); } for (i = 0; i < no_threads; i++) if (pthread_join(thread[i], NUL) != 0) { perror(Pthread_join falhou); exit(1); } printf(A soma %d \n, sum) }
Exemplo em Java
public class Adder { public int [] array; private int sum = 0; private int index = 0; private int number_of_threads = 10; private int threads_quit; public Adder () { threads_quit = 0; array = new int[1000]; initializeArray(); startThreads() } public synchronized int getNextIndex() { if (index < 1000) return (index ++); else return (-1); } public synchronized void addPartialSum(int partial_sum) { sum = sum + partoal_sum; if (++threads_quit == number_of_threads) System.out.println(a soma dos nmeros e+sum); }
private void initializeArray() { int i; for (i = 0; i < 1000; i+=) array[i] = i; } public void startThreads () { int i = 0; for (i = 0; i < 10; i++) { AdderThread at = new adderThread(this, i); at.start(); } } public static void main(String args[]) { Adder a = new Adder(); } }
class AdderThread extends Thread { int partial_sum = 0; Adder_parent; int number; public AdderThread (Adder parent, int number) { this.parent = parent; this.number = number; } public void run () { int index = 0; while (index != -1) { partial_sum = partial_sum + parent.array[index]; index = parent.getNextIndex(); } parent.addPartialSum(partial_sum);) System.out.println(Soma parcial da thread + number + + partial_sum); } }