Você está na página 1de 4

Aplicação de Teste Estrutural para Programas Multithreads Baseados em

Semáforos∗

Felipe Santos Sarmanho Paulo Sérgio Lopes de Souza Simone do Rocio Senger de Souza
Adenilso da Silva Simão

Instituto de Ciências Matemáticas e de Computação – Universidade de São Paulo


Cx. Postal 668 - 13560-970 - São Carlos - SP - Brasil
{sarmanho, pssouza, srocio, adenilso}@icmc.usp.br

Resumo O teste de programas tem por objetivo principal executar


um programa com a intenção de encontrar defeitos e é uma
Programas concorrentes são importantes para reduzir o das atividades que cooperam para garantir a qualidade de soft-
tempo de resposta de diversos tipos de aplicações. Porém, o ware [5]. O teste estrutural é uma das técnicas, dentre várias,
teste desses programas é muito difícil devido a características que tem foco na estrutura interna (código-fonte) do programa
como comunicação, sincronização e não-determinismo. Este em teste.
trabalho apresenta a aplicação do modelo de teste P CF G O teste de programas concorrentes, em geral, é abordado a
(Parallel Control Flow Graph), proposto para programas partir das propostas e conhecimentos adquiridos com o teste
concorrentes com passagem de mensagem, em programas de programas seqüenciais tradicionais. Porém, há desafios
concorrentes com memória compartilhada. O principal obs- adicionais impostos por características particulares dos pro-
táculo é a representação da comunicação, que em passagem gramas concorrentes, entre elas, o não-determinismo, comu-
de mensagem ocorre de forma explícita e em memória com- nicação, sincronização e concorrência.
partilhada ocorre implicitamente. É mostrada a viabilidade Em relação ao teste de programas multithread, a comuni-
da representação de programas concorrentes com memória cação, que ocorre de forma implícita através do uso de va-
compartilhada através do P CF G. Porém destaca-se a ne- riáveis compartilhadas, torna essa atividade ainda mais com-
cessidade de extensões para evidenciar informações relati- plexa. Alguns trabalhos relacionados para tratar o teste estru-
vas à comunicação. Um protótipo da ferramenta, denomi- tural de programas multithreads têm sido apresentadas. Essas
nada ValiPhtread, para automatizar a aplicação do modelo propostas podem ser subdivididas de acordo com a forma em
de teste P CF G em programas multithreads está em desen- que o programa em teste é executado. São elas: a execu-
volvimento. ção não-determinística, em que o programa é executado li-
vremente e depois são capturadas informações da execução
para análise [7]; execução determinística, em que, de alguma
forma, é garantida a execução de determinado fluxo de con-
1 Introdução trole e interação entre as tarefas [8, 2]; e uma forma híbrida
Um programa concorrente é composto por um conjunto de denominada teste de alcançabilidade, em que apenas porções
tarefas (threads ou processos) que interagem entre si para re- do programa são executadas deterministicamente [4].
alização de um trabalho maior. Um programa multithread é No trabalho de Vergilio et al. [7] há a proposta de um
um tipo especial de programa concorrente composto por dife- modelo de teste para tratar o teste estrutural de programas
rentes linhas de execução chamadas threads, as quais compar- concorrentes que utilizam o paradigma de passagem de men-
tilham um mesmo espaço de endereçamento . Por thread (ou sagem. Com base nesses trabalhos, este artigo apresenta o
processo leve) entende-se um fluxo de controle independente uso desse modelo de teste para testar programas concorren-
dentro do programa [3]. Programas concorrentes são uma al- tes que utilizam o paradigma de memória compartilhada. São
ternativa para reduzir o tempo de resposta de aplicações que discutidas inicialmente características comuns e semelhantes
possuem alto custo computacional, como por exemplo: quí- entre ambos os paradigmas de programação que tornam viá-
mica quântica, previsão do tempo, simulações, entre outras. vel a aplicação do modelo com poucas modificações.
O artigo está organizado da seguinte forma. Na Seção 2 é
∗ Este trabalho conta com apoio financeiro do CNPq e da FAPESP. apresentado, em linhas gerais, o padrão Pthread (POSIX Th-
read) e o conjunto de primitivas que foram consideradas neste balho. Maiores detalhes sobre esse modelo de teste P CF G
trabalho. Na Seção 3 é apresentado o modelo de teste P CF G podem ser obtidos em [7].
(Parallel Control Flow Graph) definido em [7], o qual foi to- O modelo considera que o programa concorrente, P rog =
mado como base neste trabalho. Na Seção 4 são mostradas as {p0 , p1 , .., pn−1 }, possui um número n fixo de processos e
considerações feitas a fim de viabilizar a aplicação do modelo que n é conhecido estaticamente no momento de execução
de teste a programas multithreads e na Seção 5 são apresen- do programa. A comunicação entre os processos ocorre por
tados os pontos que precisam ser tratados para viabilizar a re- meio de primitivas send e receive.
presentação total de programas multithreads. Por fim, na Se- O modelo prevê a construção do P CF G pela conexão do
ção 6 são apresentadas as conclusões e direções futuras para CF Gp (Control FLow Graph) de cada processo p por meio
o trabalho. de arestas de sincronização que representam a comunicação
entre os processos concorrentes. Cada processo p possui um
2 Padrão PThread CF Gp construído usando as mesmas regras definidas para
programas seqüenciais em que nós representam comandos do
O PThread (POSIX Thread) é uma biblioteca de threads
processo e arestas representam a transferência de fluxo de
que segue o padrão POSIX (IEEE Std 1003.1). Essa bibli-
controle [6]. Os nós que representam as primitivas sends e re-
oteca permite ao programador explicitamente construir um
ceives são representados no grafo por nós isolados. As arestas
programa concorrente na linguagem C ANSI. O Pthread de-
de sincronização são obtidas ligando os nós que representam
fine primitivas para criação e finalização de threads, assim
sends aos receives, tal que representem um possível par de
como diversas primitivas para sincronização (semáforo, mu-
sincronização.
tex e variável de condição). Também fornece diversas outras
No P CF G o i-ésimo nó do p-ésimo processo é represen-
funções que permitem, por exemplo, manipular os atributos
tado por npi , ou simplesmente ip . O conjunto N denota o
de uma thread. No entanto, nenhuma função é fornecida para
conjunto de nós do P CF G e é dividido em dois subconjun-
realizar a comunicação entre threads uma vez que espera-
tos: Ns conjunto dos nós send e Nr conjunto dos nós receive.
se que programas multithreads façam a comunicação através
O conjunto E denota o conjunto de arestas. EIp denota o con-
de variáveis compartilhadas (declaradas no escopo global do
junto de arestas intra-processo pertencentes ao processo p, en-
programa).
quanto que Es denota o conjunto de arestas de sincronização
Neste trabalho decidiu-se abordar apenas o objeto de sin-
(inter-processo).
cronização do tipo semáforo (sem_t) e as operações sob o
Um caminho π p = {npi , ..., npj } no CF Gp é denominado
mesmo (sem_init, sem_post e sem_wait), dado sua utilidade
caminho intra-processo. Quando o caminho possui ao menos
e importância. Futuras extensões deste trabalho deverão tratar
uma aresta de sincronização é denominado inter-processo e
o padrão por completo.
denotado por Π = (π 0 , π 1 , ..., π n−1 ).
Os semáforos são objetos de sincronização que basica-
O P CF G também evidencia informações de fluxo de da-
mente controlam, dado seu valor, se uma thread deve ou não
dos da mesma forma que ocorre em programas seqüenciais
seguir sua execução. Ele funciona como um contador de to-
pela agregação ao grafo de informações de definição de va-
kens que são produzidos e consumidos pelas funções forneci-
riáveis, e uso computacional (c-uso) ou predicativo (p-uso)
das pelo padrão. No Pthread, o semáforo é representado pelo
das mesmas. O modelo prevê ainda o uso de comunicação de
tipo sem_t que é basicamente uma struct que mantém um
variáveis (s-uso).
valor inteiro.
A função sem_init é responsável por atribuir o valor inicial Por meio desse modelo de teste, o testador pode gerar ca-
do semáforo. A função sem_post incrementa de um o valor sos de teste para executar os caminhos do P CF G e, desse
do semáforo. E a função sem_wait faz o decremento de um no modo, cobrir informações relevantes sobre o programa con-
valor do semáforo se o valor deste for maior que zero, caso corrente.
contrário a thread é bloqueada até que seja possível fazer o
decremento. Essas funções, em geral, são indivisíveis a fim 4 Mapeamento Multithread/PCFG
de garantir a integridade do semáforo.
Esta seção apresenta o mapeamento possível de um pro-
grama multithread, implementado usando a biblioteca Pth-
3 Modelo de Teste read, para o modelo P CF G.
O modelo de teste definido em Vergilio et al. [7] trata pro- Da mesma forma que no modelo de teste definido em Ver-
gramas concorrentes que utilizam o paradigma de passagem gilio et al. [7], considera-se aqui que o número n de threads
de mensagem. O modelo de teste é denominado P CF G (Pa- do programa multithread P C = {t0 , t1 , ..., tn−1 } é fixo e co-
rallel Control Flow Graph) e tem por objetivo explicitar in- nhecido estaticamente.
formações sobre o fluxo de controle, dados e comunicação do Para exemplificar o processo de mapeamento considere o
programa concorrente. Esta seção apresenta os conceitos fun- programa da Listagem 1. Este programa implementa o pro-
damentais desse modelo, os quais serão utilizados neste tra- blema do produtor/consumidor com buffer limitado. Três th-

2
reads participam da computação. A thread mestre (T 0) é res- aresta de sincronização em que o nó 101 representa a função
ponsável por inicializar as variáveis, criar e esperar a finaliza- sem_post (send) e o nó 52 representa a função sem_wait (re-
ção das threads. A thread produtora (T 1) é responsável por ceive).
inserir elementos no buffer e a thread consumidora (T 2) por
consumir os elementos do buffer. Observe que cada instrução
do programa é representada por um nó no grafo. O valor en-
tre comentários (/* e */), ao lado direito do programa, indica o
número do nó no grafo que representa a instrução. A Figura 1
apresenta o P CF G resultante do mapeamento aqui proposto.
Nessa figura as threads mestre, produtora e consumidora es-
tão representadas por T 0, T 1 e T 2, respectivamente.

Listagem 1: Programa do produtor/consumidor com buffer


limitado implementado usando a biblioteca Pthread/C.
1 # include < s t d l i b . h>
2 # include < s t d i o . h>
3 # include < p t h r e a d . h>
4 # include < s e m a p h o r e . h>
5
6 s e m _ t mutex , empty , f u l l ;
7 i n t queue [ 2 ] , a v a l ;
8 /∗ T h r e a d T1 ∗/
9 v o i d ∗p r o d u c e r ( v o i d ) { /∗ 1 ∗/
10 i n t prod = 0 , item ; /∗ 2 ∗/
11 while ( prod < 2) { /∗ 3 ∗/
12 item = rand ()%1000; /∗ 4 ∗/
13 s e m _ w a i t (& empty ) ; /∗ 5 ∗/
14 s e m _ w a i t (& mutex ) ; /∗ 6 ∗/
15 queue [ a v a l ] = item ; /∗ 7 ∗/
16 a v a l ++; /∗ 8 ∗/
17 p r o d ++; /∗ 9 ∗/
18 s e m _ p o s t (& mutex ) ; /∗ 10 ∗/
19 s e m _ p o s t (& f u l l ) ; /∗ 11 ∗/
20 }
21 pthread_exit (0); /∗ 12 ∗/
22 }
23 /∗ T h r e a d T2 ∗/
24 v o i d ∗c o n s u m e r ( v o i d ) { /∗ 1 ∗/
25 i n t c o n s = 0 , my_item ; /∗ 2 ∗/
26 while ( cons < 2) { /∗ 3 ∗/
27 s e m _ w a i t (& f u l l ) ; /∗ 4 ∗/
28 s e m _ w a i t (& mutex ) ; /∗ 5 ∗/ Figura 1: P CF G correspondente ao programa da Listagem 1.
29 c o n s ++; /∗ 6 ∗/
30 a v a l −−; /∗ 7 ∗/
31 my_item = q u e u e [ a v a l ] ; /∗ 8 ∗/ Quanto à função sem_init resolveu-se tratá-la como suces-
32 s e m _ p o s t (& mutex ) ; /∗ 9 ∗/
33 s e m _ p o s t (& empty ) ; /∗ 10 ∗/ sivas chamadas à função sem_post, ou seja, um semáforo que
34 p r i n t f ( " consumed : %d \ n " , my_item ) ; /∗ 11 ∗/
35 } é iniciado com um valor x, terá sua inicialização represen-
/∗ 12 ∗/
tada por x + 1 nós no CF Gt da thread onde ocorre a inici-
36 pthread_exit (0);
37 }
38 /∗ T h r e a d T0 ∗/
39 i n t main ( v o i d ) { alização do semáforo. Por exemplo, é o que acontece com
40 p t h r e a d _ t prod_h , c o n s _ h ;
41 aval = 0; /∗ 1 ∗/ a inicialização do semáforo empty no programa da Listagem
42 s e m _ i n i t (& mutex , 0 , 1 ) ; /∗ 2 , 3 ∗/
43 s e m _ i n i t (& empty , 0 , 2 ) ; /∗ 4 , 5 , 6 ∗/ 1. Empty é iniciado com o valor 2 (linha 43 da Listagem
/∗ 7 ∗/
1) e, portanto, é mapeado em três nós no grafo (nós 40 , 50
44 s e m _ i n i t (& f u l l , 0 , 0 ) ;
45 p t h r e a d _ c r e a t e (& prod_h , 0 , p r o d u c e r , ( v o i d ∗) 0 ) ; /∗ 8 ∗/
p t h r e a d _ c r e a t e (& cons_h , 0 , consumer , ( v o i d ∗) 0 ) ; /∗ 9 ∗/
e 60 ). Tal consideração não muda a semântica da função
46
47 p t h r e a d _ j o i n ( prod_h , 0 ) ; /∗ 10 ∗/
48 p t h r e a d _ j o i n ( cons_h , 0 ) ; /∗ 11 ∗/
49 exit (0); /∗ 12 ∗/ sem_init, pois apesar dessa ser atômica e estar representada
50 }
por x sucessivas chamadas à função sem_post que não são
atômicas, esperasse de um bom programa multithread que,
Para relacionar as funções de sincronização sem_post e de alguma forma, não haja possiblidade de acesso à um se-
sem_wait dos programas multithreads com as funções send máforo sem que esse tenha sido iniciado. Esse mapeamento
e receive dos programas que usam ambientes de passagem de foi feito partindo-se da seguinte analogia: sendo o semáforo
mensagem foi considerada a relação de causa-e-efeito entre considerado um repositório de tokens a serem produzidos e
seus pares [1]. Dessa forma a função sem_post foi mapeada consumidos pelas funções sem_post e sem_wait, respectiva-
para a função send e a função sem_wait para a função receive. mente, a função sem_init pode ser avaliada como a produção
Sendo assim para cada thread t constrói-se seu CF Gt sob (sem_post) sucessiva de x tokens.
as mesmas regras aplicadas aos programas seqüenciais [6]. Apesar do modelo P CF G não tratar a criação de proces-
Os nós que representam funções sem_post e sem_wait são sos, considerando que todos os processos são criados no iní-
mapeadas como nós send e receive, respectivamente. Uma cio da execução do programa concorrente, decidiu-se neste
aresta de sincronização é criada partindo do nó sem_post para trabalho tratar a criação e finalização das threads do programa
todos os nós sem_wait que fazem referência à mesma variá- multithread.
vel semáforo. Por exemplo, a aresta (101 , 52 ) representa uma A função de criação de threads (pthread_create) é tratada

3
como uma função sem_post sob um semáforo arbitrário "cre- se a thread produtora (t1 ) executa o sem_post em mutex (nó
ate_t"(com valor inicial 0) e o primeiro nó do CF Gt é tratado 101 ) e na seqüência executa o sem_wait (nó 61 ), caracteri-
com uma função sem_wait sob este semáforo. Assim a fun- zando a aresta intra-thread (101 , 61 ). Essa questão precisa
ção de criação de threads representa uma sincronização que ser adaptada para completar a representação da sincronização
informa quando uma thread está apta a iniciar sua execução. de programas multithreads por meio do P CF G.
Por exemplo, a aresta (80 , 11 ) representa uma aresta de sin-
cronização relativa à criação da thread t1 . 6 Conclusões
Tratamento semelhante foi aplicado à função pthread_join Neste trabalho foi apresentada a aplicação do modelo de
visto que esta faz a sincronização da thread que a chamou teste P CF G em programas multithreads. O teste de progra-
com o fim da execução da thread referenciada. Assim, o nó mas concorrentes apresenta dificuldades adicionais devido a
que representa a finalização da execução de uma thread (seja concorrência, não-determinismo, comunicação e sincroniza-
por uma chamada pthread_exit, return, exit, ou algo seme- ção, características intrínsecas desse tipo de programa.
lhante) é conectado ao nó que representa a chamada à função Os resultados obtidos com a aplicação do modelo P CF G
pthread_join sob a thread finalizada. A aresta (122 , 110 ), na no contexto de programas multithreads indicam que é possí-
Figura 1, exemplifica uma aresta de sincronização relativa à vel utilizar esse modelo como base para elaboração futura de
finalização de uma thread. um modelo apropriado para esses programas. As adaptações
Por fim, agregam-se informações relativas à definição e e extensões apontadas na Seção 5 são necessárias para tratar
ao uso de variáveis (privadas e compartilhadas) ao P CF G, particularidades de programas multithreads.
segundo o modelo proposto. Os próximos passos neste trabalho envolvem o tratamento
de todas as questões levantadas neste artigo com o objetivo
5 Extensões maior de propor um modelo de teste relevante para progra-
mas multithreads considerando também trabalhos correlatos
O mapeamento de programas multithreads para o modelo [7, 8, 4, 2]. Também serão estudados e adaptados os critérios
P CF G indica que é factível usá-lo no contexto de programas de teste propostos em Vergilio et al. [7] para o contexto de
multithreads. Para tanto, algumas adaptações são necessárias programas multithreads. Um protótipo da ferramenta, deno-
a fim de tratar características próprias desses programas. minada ValiPthread, para automatizar a aplicação do modelo
A primeira adaptação se faz necessária para recuperar in- está em sua fase inicial de desenvolvimento.
formações referentes à comunicação que ocorre em progra-
mas multithreads. Quando são considerados programas con-
Referências
correntes com passagem de mensagem, o modelo P CF G
trata ambas as comunicações e sincronizações com o uso das [1] R. H. Carver and K.-C. Tai. Modern Multithreading: Im-
arestas do tipo s-uso dado que essas arestas associam nós send plementing, Testing, and Debugging Multithreaded Java and
a nós receive. Quando há o casamento de sends e receives é C++/Pthreads/Win32 Programs. Wiley-Interscience, 2005.
caracterizada uma comunicação e uma sincronização. Assim, [2] O. Edelstein, E. Farchi, E. Goldin, Y. Nir, G. Ratsaby, and S. Ur.
a comunicação é explícita e evidenciada pelo P CF G. Em Framework for testing multi-threaded Java programs. Con-
programas multithread a ocorrência de uma sincronização currency and Computation: Practice and Experience, 15(3–
sob semáforos não envolve explicitamente uma comunicação. 5):485–499, Mar./Apr. 2003.
[3] A. Grama, A. Gupta, G. Karypis, and V. Kumar. Introduction to
A comunicação ocorre implicitamente, por meio de definição
Parallel Computing. Addison-Wesley Publishing; 2nd edition,
e uso de variáveis compartilhadas, e o modelo P CF G não é One Jacob Way, Reading, MA 01867-3999, second edition, Jan.
capaz de explicitar essa informação. Por exemplo, os nós 71 2003.
(definição) e 82 (uso) no grafo da Figura 1 caracterizam uma [4] Y. Lei and R. Carver. Reachability testing of concurrent
possível comunicação sob a variável queue. Assim, deverão programs. Software Engineering, IEEE Transactions on,
ser elaborados meios de evidenciar a comunicação. 32(6):382–403, June 2006.
A segunda adaptação necessária refere-se à ocorrência de [5] R. S. Pressman. Software Engineering: A Practitioner’s Appro-
ach. McGraw-Hill, New York, NY, sixth edition edition, 2005.
arestas de sincronização intra-thread. O modelo P CF G não
[6] S. Rapps and E. Weyuker. Selecting software test data using
prevê que um processo possa, em um primeiro momento, data flow information. Software Engineering, IEEE Transacti-
enviar uma mensagem e, em um momento subseqüente, o ons on, SE-11(4):367–375, April 1985.
mesmo processo receber a mensagem. Então as arestas de [7] S. R. Vergilio, S. R. S. Souza, and P. S. L. Souza. Cove-
sincronização são sempre inter-processos. No entanto, em rage testing criteria for message-passing parallel programs. In
programas multithreads é comum que uma thread que faça o LATW2005 - 6th IEEE Latin-American Test Workshop, pages
sem_post em um semáforo em seguida faça o sem_wait sob 161–166, Salvador, Ba, 2005.
[8] C.-S. D. Yang and L. L. Pollock. All-uses testing of shared
o mesmo semáforo, ou seja, a mesma thread que produz um
memory parallel programs. Softw. Test, Verif. Reliab, 13(1):3–
token o consome. Neste caso estaria caracterizada uma aresta
24, 2003.
de sincronização intra-thread. Na Figura 1 é o que acontece

Você também pode gostar