Você está na página 1de 12

CENTRO FEDERAL DE EDUCAÇÃO TECNOLÓGICA DE MINAS GERAIS

CAMPUS VII - UNIDADE TIMÓTEO - Engenharia de Computação


Sistemas Distribuídos
Lucas Pantuza Amorim

Trabalho Prático 5:
Solução concorrente para identificação de números primos

Diêgo Gomes Piovezana, Habacuque Boy Barbosa Neves

1 Introdução

Este trabalho prático possui como objetivo realizar o desenvolvimento de uma aplicação concorrente
para o problema da identificação dos n-primeiros números primos, na qual será executado por tem-
pos distintos com diferentes quantidades de threads e comparada uma solução sequencial com uma
solução paralela (concorrente).

2 Metodologia

Utilizando o compilador g++ da linguagem c++ num ambiente Linux e fazendo uso da biblioteca de thre-
ads intitulada pthread, foi elaborado um programa que recebe um número arbitrários de threads como
argumento. Em casa de ausência de argumento, a solução sequencial do programa será executada.

O programa abrirá um quantidade de threads, cada uma acessando de forma concorrente uma variável
que indica um número a ser verificado como primo. A thread pega este número, incrementa a variável
para as outras threads realizarem a verificação do próximo e calcula se ele é primo. Em caso positivo,
realiza a impressão na tela (ou salvamento em arquivo) juntamente com o id da thread. Para gerenciar
o acesso concorrente (a variável que guarda o número e o print do resultado na tela) foram utilizados
mutexes da pthread.

Na abordagem sequencial, apenas foi utilizado um FOR que efetua a divisão com todos os números
menores ao número que está verificando se é primo. Caso seja possível apenas duas divisões sem resto
(divisão por 1 e o próprio número), concluímos que de fato é um número primo. Portanto, efetua a
Sistemas Distribuídos
Lucas Pantuza Amorim

impressão do número e o incrementa (para realizar outra verificação). O programa está programado
para fazer isso infinitamente, até que seja encerrado manualmente,

Finalizado a parte da implementação, partimos para a coleta dos dados. Para isso, fazendo uso do
terminal do Linux, utilizamos o comando ”g++ -o tp5 main.cpp -l pthread” para compilar o programa
e então ”./tp5 24 > Resultados/30min_24threads.txt” para iniciar. Esse comando executa o programa
por meio do arquivo chamado ’tp5’ fazendo uso de 24 threads, durante 30 minutos e salva em arquivo
’.txt’ para que possamos comparar a quantidade de números primos encontrados em cada situação
posteriormente. Repare que, o processo de execução é manual, desta forma, com o auxílio de um
cronômetro, o programa foi também manualmente encerrado (Ctrl + C).

O programa foi executado por 30 minutos com 24, 12, 6, 3 e 1 thread. Posteriormente, o mesmo proce-
dimento foi realizado durante 15 minutos, 5 minutos, 1 minuto, 30 segundos, 10 segundos e 5 segundos.
Uma exemplificação dos prints realizados dentro do arquivo .txt pode ser observado na Figura 3.

Ao término da geração dos números primos nas condições apresentadas acima, precisamos contar
quantos números primos foram encontrados em cada execução. Para isso, através do comando ”wc
-l Resultados/30min_24threads.txt” contamos a quantidade de linhas e consequentemente de núme-
ros primos encontrados (cada linha possui a impressão de um número primo). O resultado pode ser
observado na Figura 4 presente na seção de resultados.

Por fim, com o objetivo de comparar as diferentes abordagens, foi então gerado alguns gráficos que
podem ser conferidos a partir da figura 7 presente na seção Resultados abaixo.

3 Resultados

Após desenvolvimento do sistema, o resultado pode ser observado abaixo:


Sistemas Distribuídos
Lucas Pantuza Amorim

3.1 Execução do programa

Figura 1: Comandos para compilar e iniciar o programa

3.2 Coleta dos dados

Figura 2: Comando para iniciar e salvar os nº primos no arquivo


Sistemas Distribuídos
Lucas Pantuza Amorim

3.3 Arquivo txt

Figura 3: Números salvos no bloco de notas

3.4 Contagem dos números primos

Figura 4: Comando para contar a quantidade de números primos


Sistemas Distribuídos
Lucas Pantuza Amorim

3.5 Números primos encontrados em cada modalidade

Figura 5: Quantidade de nº primos para cada modalidade

3.6 Processador durante a execução do programa

(a) (b)

Figura 6: Comparação Concorrente (a) X Sequencial (b)


Sistemas Distribuídos
Lucas Pantuza Amorim

3.7 Gráficos

Figura 7: Gráficos com o comportamento da execução do programa durante diferentes tempos


Sistemas Distribuídos
Lucas Pantuza Amorim

4 Análise

Esperava-se que a solução concorrente fosse capaz de encontrar uma quantidade superior à solução
sequencial e observamos que tal comportamento se confirmou. Porém, esperava-se que quanto maior
a quantidade de threads, maior a quantidade de números primos encontrados no mesmo intervalo de
tempo, porém isto não ocorreu. Percebe-se portanto que a quantidade de números a serem encontra-
dos não está relacionado com a quantidade de threads, mas sim, como estas foram programadas em
harmonia com o tempo dedicado a execução das mesmas.

5 Conclusão

Após realização do trabalho prático concluímos que, de fato a solução concorrente foi capaz de desco-
brir uma quantidade superior de números primos se comparado a versão sequencial. Adicionalmente,
observamos ainda, de maneira prática, através da utilização um gerenciador de tarefas, que a solução
concorrente faz melhor uso dos núcleos do processador, diferentemente da solução sequencial, justifi-
cando portanto tal comportamento.

6 Código

Todo programa foi implementado em um único arquivo (main.cpp), que pode ser obervada abaixo:
1 / / b i b l i o t e c a n a t i v a de m a t e m a t i c a do C
2 # i n c l u d e < math . h >
3
4 / / l i b de t h r e a d s do C
5 #include < pthread . h>
6

7 / / b i b l i o t e c a n a t i v a de f u n c i o n a l i d a d e s b a s i c a s de i o C + +
8 #include < iostream >
9
10 / / p a r a n a o p r e c i s a r p o r s t d a n t e s d a s f u n c o e s da l i b anterior
11 u s i n g namespace s t d ;
12

13 / / a l i a s p a r a um i n t e i r o p o s i t i v o m u i t o g r a n d e
14 using b i g I n t = unsigned long long ;
15
16 / / n u m e r o a t u a l p a r a c h e c a r s e eh p r i m o
Sistemas Distribuídos
Lucas Pantuza Amorim

17 b i g I n t num = 1 ;
18
19 / / r e f e r e n c i a ao m u t e x de a c e s s o ao n u m e r o
20 p t h r e a d _ m u t e x _ t num_mutex ;
21 / / m u t e x p a r a p r i n t a r na t e l a
22 / / c o u t e m b o l a d a d o s de m u l t i p l a s t h r e a d s
23 pthread_mutex_t print_mutex ;
24

25 / / r e t o r n a t r u e ou f a l s e i n d i c a n d o s e o n u m e r o eh p r i m o
26 / / r e c e b e um n u m e r o i n t e i r o n a o n e g a t i v o
27 b o o l e h P r i m o ( b i g I n t num ) {
28
29 / / 0 e 1 n o s o primos
30 i f ( num < = 1 ) r e t u r n f a l s e ;
31
32 / / o maximo d i v i s o r p o s s i v e l de um n u m e r o eh a r a i z q u a d r a d a d e l e msm
33 / / nesse ’ f o r ’ tentamos todas a d i v i s o e s p o s s i v e i s
34 f o r ( i n t d i v i s o r = 2 ; d i v i s o r < = s q r t ( num ) ; d i v i s o r + + ) {
35 / / s e d i v i s a o n a o t e r r e s t o o n u m e r o n a o eh p r i m o
36 i f ( num % d i v i s o r = = 0 ) r e t u r n f a l s e ;
37 }
38
39 / / nenhuma d i v i s a o foi sucedida , n u m e r o eh p r i m o
40 return true ;
41 }
42

43 / / c h e c a s e o n u m e r o a t u a l eh p r i m o
44 / / r e c e b e o i d da t h r e a d que chamou a f u n c a o
45 void checaAtual ( int id ) {
46
47 / / a c e s s o e x c l u s i v o a num n e s s e t r e c h o
48 p t h r e a d _ m u t e x _ l o c k ( & num_mutex ) ;
49 / / pega o numero a t u a l p a r a c h e c a r
50 b i g I n t c h e c a r = num ;
51 / / muda p a r a o s o u t r o s c h e c a r e m o p r o x i m o n u m e r o
52 num + + ;
53 / / l i b e r a a c e s s o ao num
54 p t h r e a d _ m u t e x _ u n l o c k ( & num_mutex ) ;
55
56
57 / / i m p r i m e o numero c h e c a d o s e f o r p r i m o
58 i f ( ehPrimo ( checar ) ) {
59 / / a c e s s o e x c l u s i v o a s a i d a do r e s u l t a d o n e s s e t r e c h o
60 pthread_mutex_lock (& print_mutex ) ;
61 cout << id << " : " << checar << endl ;
62 / / l i b e r a a c e s s o ao p r i n t do r e s u l t a d o
63 pthread_mutex_unlock (& print_mutex ) ;
64 }
Sistemas Distribuídos
Lucas Pantuza Amorim

65
66 }
67

68 / / f u n c a o que vamos e x e c u t a em c a d a t h r e a d
69 void * thread ( void * thread_id ) {
70 // converte o ponteiro recebido
71 / / p a r a um p o n t e i r o de i n t e i r o
72 // e e x t r a i o valor naquele endereco
73 int id = *( ( int *) thread_id ) ;
74 / / f i c a para sempre checando primos
75 while ( true ) { checaAtual ( id ) ; }
76 r e t u r n NULL ;
77 }
78

79
80 void sequencial () {
81
82 int i = 2 , totalDivisores , j ;
83
84 while ( true )
85 {
86 t o t a l D i v i s o r e s = 0;
87
88 / / Conta os d i v i s o r e s para v e r i f i c a r se o v a l o r primo
89 for ( j = 1 ; j <= i ; j + + )
90 {
91 if ( i % j = = 0)
92 { // Se r e s t o z e r o
93 totalDivisores ++;
94 }
95 }
96 / / Se o t o t a l de d i v i s o r e s dois , primo
97 i f ( t o t a l D i v i s o r e s == 2)
98 {
99 p r i n t f ( " %4d \ n " , i ) ; / / I m p r i m e o p r i m o com f o r m a t a o de 4
casas
100 }
101

102 i ++; // Pr ximo n mero a ser analisado


103 }
104
105
106 }
107

108
109 / / f u c n a o p r i n c i p a l , r e c e b e o n u m e r o de a r g u m e n t o s de l i n h a de comando
110 / / e q uai s sao e s s e s argumentos
111 i n t main ( i n t a r g c , c h a r * a r g v [ ] ) {
Sistemas Distribuídos
Lucas Pantuza Amorim

112
113 / / / / s e o n u m e r o de t h r e a d s n a o f o r p a s s a d o como a r g u m e n t o e n c e r r e o
programa
114 // i f ( argc < 2 ) {
115 // c o u t < < " p a s s e o n u m e r o de t h r e a d s " < < e n d l ;
116 // return 1;
117 // }
118

119 / / s e o n u m e r o de t h r e a d s n a o f o r p a s s a d o como a r g u m e n t o , e x e c u t a a
v e r s o sequencial
120 i f ( argc < 2 ) {
121 sequencial () ;
122 }
123

124
125 / / s a l v a o n u m e r o de t h r e a d s
126 / / o a r g u m e n t a c h e g a como s t r i n g , c o n v e r t e m o s e l e p a r a um i n t e i r o
127 / / um a r g u m e n t o i n v a l i d o r e t o r n a 0
128 i n t n _ t h r e a d s = s t r t o l ( a r g v [ 1 ] , NULL , 1 0 ) ;
129

130 / / se f o r 0 t h r e a d s ( argumento i n v a l i d o )
131 // consideramos 1 thread
132 i f ( n _ t h r e a d s <= 1 ) n _ t h r e a d s = 1 ;
133
134 / / i n i c i a m u t e x do p o s s i v e l num p r i m o , s e f a l a r e n c e r r a o p r o g r a m a
135 i f ( p t h r e a d _ m u t e x _ i n i t ( & num_mutex , NULL ) ! = 0 ) {
136 c o u t < < " f a l h a na i n i c i a l i z a o do m u t e x de num " < < e n d l ;
137 return 3;
138 }
139
140 / / i n i c i a m u t e x de p r i n t , se f a l a r e n c e r r a o programa
141 i f ( p t h r e a d _ m u t e x _ i n i t ( & num_mutex , NULL ) ! = 0 ) {
142 c o u t < < " f a l h a na i n i c i a l i z a o do m u t e x de p r i n t " < < e n d l ;
143 return 4;
144 }
145
146 / / v e t o r de r e f e r e n c i a s de t h r e a d s
147 pthread_t * threads = ( pthread_t *) malloc ( sizeof ( pthread_t *) *
n_threads ) ;
148 / / abre as threads
149 f o r ( i n t i = 0 ; i < n_threads ; i ++ ) {
150 / / i d da t h r e a d
151 / / p e g a um e n d e r e c o de m e m o r i a p a r a g u a r d a r i n t e i r o
152 i n t * id = ( i n t *) malloc ( sizeof ( i n t *) ) ;
153 / / g u a r d a v a l o r de i n a q u e l e e n d e r e c o
154 * id = i ;
155 // c r i a a thread
156 / / s e f a l h a r s a i do p r o g r a m a
Sistemas Distribuídos
Lucas Pantuza Amorim

157 i f ( p t h r e a d _ c r e a t e ( & t h r e a d s [ i ] , NULL , & t h r e a d , ( v o i d * ) i d ) )


{
158 c o u t < < " f a l h a na c r i a o de t h r e a d s " < < e n d l ;
159 return 4;
160 }
161 }
162
163 / / espera as threads
164 / / espera a thread , se f a l h a r encerramos o programa
165 f o r ( i n t i = 0 ; i < n_threads ; i ++ ) {
166 i f ( p t h r e a d _ j o i n ( t h r e a d s [ i ] , NULL ) ) {
167 c o u t < < " f a l h a na s i n c r o n i z a o de t h r e a d s " < < e n d l ;
168 return 5;
169 }
170 }
171
172 r e t u r n 0;
173 }

codigo/main.cpp
Sistemas Distribuídos
Lucas Pantuza Amorim

Referências
[1] Greg Ippolito. POSIX thread (pthread) libraries, 2004. URL
https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html.

[2] Rahul Jain. Multithreading in C - GeeksforGeeks, 10 2018. URL


https://www.geeksforgeeks.org/multithreading-c-2/.

[3] Oracle Corporation and/or its affiliates. Mutex Lock Code


Examples (Multithreaded Programming Guide), 2010. URL
https://docs.oracle.com/cd/E19455-01/806-5257/sync-12/index.html.

[4] Kishlay Verma. Mutex lock for Linux Thread Synchronization - GeeksforGeeks, 11 2019. URL
https://www.geeksforgeeks.org/mutex-lock-for-linux-thread-synchronization/.

Você também pode gostar