Objetivo Universidade Federal do ABC Disciplina: BC 1518 Sistemas Operacionais (SO) Prática: Processo/Threads Atividade 3 Trabalhando com Processos e Threads em Ambiente LINUX 1.Trabalhar com comandos de manipulação de prioridade de processos; 2. Estudo e teste inicial com pthreads 1. Processos 1- O comando nice atribui um número de prioridade para um processo. Por padrão os processos de usuários são criados com prioridade 0 (zero). Utilize esse comando para inicializar o editor vim com o nível de prioridade 6? Descreva o comando utilizado: A prioridade atribuida é alta ou baixa? obs.: Utilize o comando ps -lax grep vim para verificar a prioridade atribuída ao processo. 2 - O comando renice altera a prioridade de um processo em execução. Utilize esse comando para alterar a prioridade do vim para 7? Descreva o comando utilizado: obs.: o comando ps -lax grep vi para determinar o número do processo. Maiores informações sobre sintaxe, parâmetros, condições de erro podem ser obtidas nas manpages. 3- Programa 1: #include <sys/types.h> #include <unistd.h> pid_t pid; printf("processo pai. PID = %d\n", getpid()); pid = fork(); printf("pid = %d\n",pid); if (pid!= 0) printf("processo pai. PID do filho = %d\n", pid); else printf("processo filho. PID = %d\n", getpid()); 1
Execute o programa. Descreva o que esta ocorrendo? Que comando devo utilizar para criar mais um processo nesse programa? 4. Programa 2: #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> pid_t pid; printf("processo pai. PID = %d\n", getpid()); if ((pid = fork())!= 0) { printf("processo pai. PID do filho = %d\n", pid); wait(null); printf("meu filho morreu\n"); else { sleep(2); /* Filho demora um pouco para executar. */ printf("processo filho. PID = %d\n", getpid()); Implemente esse código Execute o programa. O que esta acontecendo? Qual a finalidade da função wait nesse programa? Se mudar essa instrução por wait4. Qual será o resultado? 2. Threads 5. Threads: Como vimos em aula teórica, um único processo podemos ter vários fluxos escalonáveis de execução, que compartilham uma mesma área de código e dados, mas cada qual tem de forma independente seu próprio contexto, pilha e program counter (PC). Nesse item, faremos uso da biblioteca conhecida como POSIX Threads ou popularmente pthreads. Todo programa em C que usa pthreads deve incluir o arquivo <pthread.h> no início. Para compilar os programas criados em linguagem C, digite: gcc -o nome_do_aplicativo nome_do_programa.c Se estiver trabalhando com thread inclua a opção -lpthread na compilação. 2
Para criarmos uma nova thread usamos a função pthread_create(*t,*a, rotina, arg), onde os argumentos são: t é um ponteiro para uma variável do tipo pthread_t que conterá o identificador da thread recém criada; a é um ponteiro para os atributos da thread. Os atributos são armazenados em uma variável do tipo pthread_attr_t. Um valor NULL indica o uso de valores default. Para detalhes veja pthread_attr_init. 2. rotina é o nome (ponteiro) para a rotina (função) que define o comportamento da thread. arg é um void * que é passado como argumento para a rotina. A nova thread é disparada imediatamente e termina no retorno da função ou pela chamada da função pthread_exit(*ret). Seu argumento, ret aponta uma variável que armazenará o valor de retorno, já que pthread_exit nunca retorna. pthread_exit é de certa forma o equivalente à função exit. Em princípio, uma thread criada desta forma está preparada para sincronização ao final. Este estado é chamado de joinable. Deve haver uma chamada a pthread_join para liberar totalmente os recursos alocados depois do término. Se não houver necessidade de sincronização, pode-se "desconectar" a thread com a função pthread_detach(id). Isto impede a sincronização por join no final da execução mas por outro lado libera os recursos imediatamente, impedindo que esta thread possa ser reconfigurada para um join. Para fazer a sincronização de término com uma thread, usa-se: pthread_join(pthread_t id, void **return); return apontará para o valor de retorno da thread e pode ser NULL. Neste caso o valor de retorno é descartado. Implemente agora o programa abaixo para avaliarmos o comportamento. Complete a função pthread_create. #include <pthread.h> void* f_thread(void *v) { printf("nova Thread.\n"); return NULL; pthread_t thr; 3
if (pthread_create(&thr, NULL, )) fprintf(stderr, "Erro na criação da thread. \n"); 6. Para avaliarmos seu comportamento com multithreading, implemente o programa abaixo. Uma vez executado faça a experiência de remover a linha de código error = pthread_join(tid,null); e avalie novamente comportamento do programa. Em seguida, repita o procedimento mas substitua o código supracitado por error = pthread_detach(tid,null). O que ocrre se modificarmos o valor da função sleep para 10. Utilieza a chamada time para capturar o tempo de execução. Por exemplo: $ time./thread. #include <pthread.h> int count = 0; void work(void) { pthread_t tid; tid = pthread_self(); printf("i am a worker thread %d - count = %d\n", (int) tid, count++); sleep(1); int error,i,n; pthread_t tid,mytid; printf("enter number of threads: "); scanf("%d",&n); mytid = pthread_self(); printf("thread %d is creating threads\n",(int) mytid); for (i=1;i<=n;i++) { error = pthread_create(&tid, NULL,(void *(*)(void *))work, NULL); printf("created thread %d\n",(int) tid); error = pthread_join(tid,null); printf("done forking and joining threads\n"); 4
5