E.E.E.P. Dr. Solon Tavares Sistemas Operacionais Prof. Henrique Cordeiro. Programação Concorrente em Linux



Documentos relacionados
Um processo sob UNIX ocupa uma área de memória formada basicamente por 3 partes:

Processos em Unix. Conteúdo: Definição de Processos em Unix Estrutura, tipo e escalonamento de processos em Unix Processos, Pai, Filho e Zumbi.

Manipulação de processos

Sistemas Operacionais

Conceitos de Sistemas Operacionais: Chamadas de Sistema. Prof Rafael J. Sandim

Processos. Estados principais de um Processo: Contexto de um Processo. Nível de um Processo.

SISTEMAS OPERACIONAIS CAPÍTULO 3 CONCORRÊNCIA

Orientação a Objetos

ESTRUTURA DE UM SISTEMA OPERACIONAL

UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL INSTITUTO DE INFORMÁTICA INFORMÁTICA APLICADA


Sistema Operacional Ex: Complexo Computador multiusuário com vários terminais Tem que administrar todos os pedidos de usuários e assegurar que eles

Projeto: Camada Independente de Dispositivo

Processos e Threads (partes I e II)

IFPE. Disciplina: Sistemas Operacionais. Prof. Anderson Luiz Moreira

Procedimentos para Reinstalação do Sisloc

Sistemas Operacionais. Prof. M.Sc. Sérgio Teixeira. Aula 04 - Concorrência. Cursos de Computação

Máquina de estados UNIX O

Máquina de estados UNIX O. Sistemas Operacionais 2008/1Profa. Patricia S.O. computação: recursos D. S.O S.O. controla eventos no sistema de

Sistema de Arquivos FAT

2. OPERADORES ALGORITMOS, FLUXOGRAMAS E PROGRAMAS FUNÇÕES... 10

3. Arquitetura Básica do Computador

Programação Orientada a Objetos com PHP & MySQL Cookies e Sessões. Prof. MSc. Hugo Souza

Sistemas Operacionais. Prof. André Y. Kusumoto

Funções de um SO. Gerência de processos Gerência de memória Gerência de Arquivos Gerência de I/O Sistema de Proteção

SISTEMAS OPERACIONAIS 2007

LP II Estrutura de Dados. Introdução e Linguagem C. Prof. José Honorato F. Nunes honorato.nunes@ifbaiano.bonfim.edu.br

Sistemas Operacionais

GABARITO COMENTADO SISTEMAS OPERACIONAIS. PROF. Cláudio de C. Monteiro, Evanderson S. de Almeida, Vinícius de M. Rios

Sistemas Operacionais

SVCs para Controle de Processos no Unix (cont.) Sistemas Operacionais

Entrada e Saída. Prof. Leonardo Barreto Campos 1

Arquitetura de Rede de Computadores

Sistemas Operacionais e Introdução à Programação. Programação com linguagem C

Programação de Sistemas

TUTORIAL PRÁTICO SOBRE Git. Versão 1.1

Ciclo de Vida de um Processo

! Os primeiros computadores permitiam a execução de apenas um programa de cada vez, com acesso completo aos recursos do sistema

Processos. Adão de Melo Neto

Prof. Raul Sidnei Wazlawick UFSC-CTC-INE. Fonte: Análise e Projeto de Sistemas de Informação Orientados a Objetos, 2ª Edição, Elsevier, 2010.

INF 1005 Programação I

Procedimentos para Instalação do Sisloc

Configuração do Ambiente de Trabalho

Exercício 1. Tabela 1: Cadastro de usuários, senhas e privilégios (exemplo). Login Senha Privilégio Armamento

Sistemas Operacionais

SISTEMAS OPERACIONAIS II ESPECIFICAÇÃO CAMADA INDEPENDENTE

Programação para Android. Aula 07: Persistência de dados Shared Preferences, Internal e External Storage

7 Processos. 7.1 Introdução

FundamentosemInformática

Complementos de Programação. Engenharia Electrotécnica - Electrónica e Computadores. Ano Lectivo: 2005/2006. Ana Madureira. Gestão de Processos

Orientação a Objetos

Aula 3. Sistemas Operacionais. Prof: Carlos Eduardo de Carvalho Dantas

Central Cliente Questor (CCQ) UTILIZANDO A CCQ - CENTRAL CLIENTE QUESTOR

Prof.: Roberto Franciscatto. Capítulo 1.1 Introdução

Google Drive. Passos. Configurando o Google Drive

MC102 Algoritmos e programação de computadores Aula 3: Variáveis

Java para Desenvolvimento Web

Processos. Programas e Processos. Aula 1 - Chamadas ao sistema. José Pedro Oliveira fork exit getpid, getppid wait, waitpid

Gerência de Processador

Comunicação entre Processos Canal de comunicação Arquitetura da comunicação Modelos de comunicação

Processamento com SPOOL. Utilização do CPU e periféricos. Perfis dos programas. Exemplo IBM 1460 (1963) Problemas no escalonamento.

Sistemas Operacionais INF Prof. José Gonçalves

FTP - Protocolo. O protocolo FTP é o serviço padrão da Internet para a transferência de arquivos entre computadores.

Programação de Computadores - I. Profª Beatriz Profº Israel

Arquitetura de Computadores. Introdução aos Sistemas Operacionais

Prof. Marcos Ribeiro Quinet de Andrade Universidade Federal Fluminense - UFF Pólo Universitário de Rio das Ostras - PURO

Comunicação entre pai e filho

Camadas de Transporte, Sessão & Apresentação. Função. Camadas REDES x TRANSPORTE. Redes de Computadores Prof. Leandro C. Pykosz

Sistemas Operacionais. Introdução

CAPÍTULO 2 CARACTERÍSTICAS DE E/S E PORTA PARALELA

INF 1620 P1-10/04/02 Questão 1 Nome:

Arquitetura de Sistemas Operacionais

APOSTILA LINUX EDUCACIONAL

Busca. Pesquisa sequencial

CAPÍTULO 7 NÍVEL DE LINGUAGEM DE MONTAGEM

3 SCS: Sistema de Componentes de Software

O WINDOWS 98 é um sistema operacional gráfico, multitarefa, produzido pela Microsoft.

FTP Protocolo de Transferência de Arquivos

Figura 01 Kernel de um Sistema Operacional

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br

Algoritmos e Programação Estruturada

MUDANÇAS NA ISO 9001: A VERSÃO 2015

UDPcast Clonagem de HDs via rede utilizando

16:21:50. Introdução à Informática com Software Livre

Prof. Rafael Gross.

Sistema de Arquivos. Ambientes Operacionais. Prof. Simão Sirineo Toscani

Algoritmos e Programação _ Departamento de Informática

AULA 5 Sistemas Operacionais

Processos Prof. João Paulo de Brito Gonçalves

Transcrição:

E.E.E.P. Dr. Solon Tavares Sistemas Operacionais Prof. Henrique Cordeiro Programação Concorrente em Linux O Conceito de Processo no Linux O conceito de processo é fundamental para qualquer sistema operacional multiprogramado. Essencialmente, como visto anteriormente, um processo é uma abstração que representa uma instância de um programa em execução. Os processos podem representar tanto a execução de tarefas do próprio sistema operacional como tarefas de usuários. É através desse conceito que o sistema operacional organiza suas tarefas de gerenciamento. Durante o ciclo de vida de um processo, ele utiliza vários recursos do sistema: o processador para sua execução; espaço em memória física para o armazenamento de dados e do programa em execução; descritores de arquivos; o emprego direta ou indiretamente de dispositivos de entrada e saída; etc. Para que seja possível gerenciar os recursos do sistema de forma justa, repartindo-os equitativamente entre os processos, o Linux deve ter uma idéia clara de o que cada um dos processos existentes no sistema está realizando, ou seja, qual o seu estado de execução. Essa informação é mantida em uma estrutura de dados especial: o descritor de processo. O descritor de processo é uma estrutura bastante complexa, possuindo uma série de campos tais como ponteiros para outros descritores de processos, ponteiros para descritores de arquivos abertos, ponteiros para áreas de memória em uso, informações para escalonamento, temporizadores, contexto do processo, etc. O contexto de um processo é inacessível a outros processos, do mesmo modo um processo pode apenas atuar sobre o seu contexto. Um processo se comunica com o mundo exterior sob vigilância do sistema operacional, assim assegura-se um funcionamento estável, sem interferências entre processos. Fazem parte do contexto de um processo diversos tipos de informação de controle, dentre os quais é interessante destacar o Identificador de Processo (PID). PID (Process Identifier) número inteiro positivo que identifica um dado processo. É atribuído pelo sistema operacional no momento da criação do processo.

Criação de um processo A criação de um processo, em ambientes UNIX, realiza-se da seguinte forma: um processo já existente invoca a chamada de sistema fork. Quando um processo invoca esta chamada, o sistema operacional cria uma cópia do contexto do processo corrente e atribui-lhe um novo PID, a partir desse momento existem dois processos exatamente iguais. Ao processo original (que fez a chamada fork) chamamos processo pai, ao novo processo (com o novo PID) chamamos processo filho. int fork(void); Certamente que o código que se pretende executar depois do fork é diferente para o pai e para o filho, para que o código em execução saiba qual o processo em que está basta analisar o valor de retorno do fork: Ao processo pai a chamada fork retorna o PID do filho (inteiro positivo). Em caso de erro, retorna o valor -1. Ao processo filho a chamada fork retorna o valor zero. Exemplo: pid = fork(); if(pid < 0) printf("erro no fork\n"); if(pid > 0) /* continuação do processo pai */ /* continuação do processo filho */

Qualquer processo pode obter facilmente o seu próprio PID e também o PID do seu pai. A chamada int getpid(void) devolve ao processo invocador o seu próprio PID. A chamada int getppid(void) devolve ao processo invocador o PID do seu pai. O exemplo seguinte ilustra a utilização do fork e destas duas chamadas de sistema: #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() int child_pid; printf("ainda existe apenas um processo (%d)\n",getpid()); child_pid = fork(); printf("agora somos dois (%d)\n",getpid()); if(child_pid > 0) printf("eu sou o pai(%d), meu filho é: %d\n",getpid(),child_pid); sleep(1); printf("eu sou o filho(%d), meu pai é: %d\n",getpid(),getppid()); A chamada sleep é usada para adormecer o processo pai durante um segundo, assegurando que o pai não termina antes do filho. Sincronização entre processo pai e filhos No exemplo anterior o processo pai foi suspenso durante um segundo para ter certas garantias de que o filho acabe primeiro. A consequência de isso não acontecer é que se a chamada getppid() fosse invocada depois de o pai ter terminado, devolveria um valor inesperado. Na realidade devolveria o PID do "pai do pai" já que este adotaria o "filho órfão". Existem mecanismos muitos mais eficientes para assegurar o sincronismo entre pai e filhos. A chamada wait suspende o processo pai até que um filho termine: int wait(int *); O valor de retorno desta chamada é o PID do filho que terminou. Se já não existe mais nenhum filho a chamada wait devolve o valor -1. A chamada wait tem como parâmetro um ponteiro para um inteiro que será usado para guardar o "exit-status" do filho. Este mecanismo permite ao filho, no momento em que termina, enviar ao pai um valor numérico, na prática está limitado aos 8 bits menos significativos que terão de ser obtidos utilizando a "macro": int WEXITSTATUS(int);

Os filhos transmitem ao pai o seu código de saída utilizando a chamada _exit que termina o processo: void _exit(int); Enquanto a invocação da chamada _exit não for correspondida pela chamada wait no processo pai, o processo filho fica num estado conhecido por Zombie em que não ocupa recursos. O exemplo seguinte ilustra a utilização deste tipo de mecanismo: #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main() int child_pid, ret; child_pid = fork(); if(child_pid == 0) printf("sou o filho %d\n", getpid()); _exit(0); printf("pai: lancei o filho com o PID %d\n", child_pid); child_pid = wait(&ret); ret = WEXITSTATUS(ret); printf("o filho com PID %d devolveu-me %d\n", child_pid, ret); A transferência de dados do processo pai para o filho no momento da sua criação é simples porque todos os dados definidos pelo pai são copiados para o filho. A transferência de dados do processo filho, quando este termina, para o processo pai é limitada a 8 bits. Este fato torna-se irrelevante porque existem mecanismos apropriados para a comunicação entre processos (IPC).

Funções exec Após a criação de um processo filho através de uma chamada fork, este pode ter sua área de código substituída por outro código que deve ser executado. Para tal, é utilizada a chamada exec. É esta chamada que permite ao processo filho substituir a imagem do código do pai por uma imagem própria. Por isso, encontra-se como uma referência bastante comum, no mundo UNIX, a expressão fork-exec. Todos os processos UNIX são criados desta forma. Na realidade, durante a inicialização de uma máquina, um primeiro processo é criado manualmente pelo sistema operacional. Esse processo é denominado init e recebe um identificador de processo (PID) igual a 1. O processo init cria uma série de processos todos através de fork-exec os quais serão responsáveis pela gerência do sistema. Cada processo criado recebe um PID diferente que será empregado pelo sistema operacional para referências futuras. Entre os processos criados pelo init, estão os processos associados ao programa getty. Cada instância do getty espera que sejam introduzidos o nome de um usuário e uma senha. Quando essas informações são fornecidas, o processo getty substitui seu código, através da chamada exec, pelo código do programa login. O login é responsável por autenticar um usuário, e assim permitir que o mesmo conecte-se ao sistema. O usuário sendo válido no sistema, o login é considerado com sucesso e executa novamente uma chamada exec para substituir seu código por um outro programa: o interpretador de comandos (shell). A partir do shell, o usuário pode realizar comandos. Qualquer comando executado no shell dará origem a uma sequência fork-exec, permitindo assim a criação de novos processos. Os comandos executados a partir de um shell são normalmente programas utilitários do sistema como, por exemplo, ls para listar o conteúdo de um diretório, grep para procurar ocorrências de strings em um arquivo, etc. Nesse caso, o shell cria um processo filho que executa o código associado a esse comando e faz com que o processo pai (shell, nesse caso) espere pelo término do filho. Quando o filho termina, o controle retorna ao shell (processo pai) e o usuário pode executar um novo comando. Nesse ponto, cabe um comentário: os processos executados em background. Um processo em background nada mais é que a criação de um processo filho sem que o pai espere por seu término. Dessa forma, podemos ter o processo filho executando ao mesmo tempo que o processo pai. As funções exec utilizam outra primitiva básica, embora sejam variadas na forma dos seus parâmetros, todas realizam a mesma tarefa: carregam de um arquivo binário que substitui o código e dados do contexto do processo corrente e inicia a sua execução. A menos que ocorra um erro, a execução do código no processo invocador termina. Quando se pretende executar um comando paralelamente ao processo principal basta criar um filho que invoca uma função exec. A função exec é na verdade uma família de funções, com variantes. Usaremos a seguinte função: int execlp(char *arquivo, char *argumento0,..., NULL);

Esta função recebe como parâmetros o nome do arquivo executável (também podemos utilizar o caminho completo para executar o arquivo) e possíveis argumentos. Se a variável arquivo não contém um caminho, o arquivo executável vai ser procurado nos diretórios especificados na variável ambiente PATH. A forma de indicar os argumentos varia, mas em qualquer dos casos termina com o argumento NULL. Exemplo: #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> void main() int child_pid, ret; child_pid = fork(); if(child_pid == 0) execlp("codigo_filho", "parametro1", "parametro2", NULL); printf("erro no comando exec\n"); _exit(1); child_pid = wait(&ret); ret = WEXITSTATUS(ret);

Fontes http://www.dei.isep.ipp.pt/~andre/documentos/multiprocesso.html R. Oliveira, A. Carissimi, S. Toscani. Sistemas Operacionais. 3ª Edição. Editora Sagra-Luzzato, 2004. Cláudio Geyer, Rômulo Rosinha. fork/join no UNIX, INF01151. Sistemas Operacionais II, 2006.