IPC – Comunicação entre processos Fábia Isabella Gabriel Kovalechyn Gabriel Tadra Mainginski Introdução • Há ocasiões onde é extremamente necessário que dois ou mais processos/threads acessem um único recurso comum. Caso esse tipo de paralelismo não ocorra de forma controlada, podemos fazer com que um processo "sequestre/atropele" a operação de outro. • Processos, memória compartilhada e pipes são as principais tríade de recursos compartilhados necessários em ambientes *NIX para a perfeita comunicação entre processos (IPC ou Inter-Process Communication). • Com eles, é possível acesso controlado a processos, de forma que só haverá disponibilidade quando a operação em andamento for finalizada. Semáforos • Semáforos em Linux são “sleeping locks”. Quando uma tarefa tenta obter um semáforo já em uso, o semáforo põe a tarefa na fila de espera e a põe no estado sleep, deixando o processador livre para executar outro código. Quando o processo liberar o semáforo, uma das tarefas da fila de espera é acordada e pode obter o semáforo. • Se o contador se tornar negativo, a tarefa é colocada na fila de espera. A operação up() é usada para liberar o semáforo após a tarefa completar a execução da região crítica. Isto é feito incrementando o contador; e se a fila de espera está vazia, uma das tarefas em espera é acordada e pode obter o semáforo. • Basicamente, esses semáforos funcionam como indicadores (flags) que sinalizam para o ambiente se o mesmo está ou não em utilização. Assim, o processo de sinalização requer colaboração e troca de informações entre processos. • Dependendo da quantidade de aplicações que existem no ambiente, a quantidade inicial de semáforos pode não ser suficientes para um perfeito controle de todo o sistema. Na verdade, a maioria dos sistemas operacionais modernos oferecem essas funcionalidades, porém os padrões das diversas distribuições são tão baixos que é fácil saturar esses recursos. Exemplo • Uma instalação considerável do PostGreSQL pode "extirpar" rapidamente vários limites de recursos do sistema operacional, comumente usando 1 semáforo para cada instância/requisição concorrente. Uma instalação comum de Oracle consome aproximadamente 70 semáforos. • Quando esses recursos são saturados, sua falta manifesta um erro conhecido como "Chamada de Sistema Ilegal". Nesse caso, não há nada a ser feito, a não ser remover recursos que na maioria das vezes não é possível ou recompilar o núcleo do kernel. Funções Principais • int semget ( key_t key, int nsems, int semflg ) – Pega o id do semáforo. • int semctl ( int semid, int semnum, int cmd, union semun arg ) – Inicia todos os semáforos com valores positivos. • int semop ( int semid, struct sembuf *sops, unsigned nsops) – Usado para a sincronização de processos • int sem_init(int no_of_sems, int common_intial_value) – Inicia semáforo(s). • void sem_change(int sem_id, int sem_no, int amount)– Muda semáforos. • int sem_try_change(int sem_id, int sem_no, int amount) - Muda semáforos ignorando erros • int sem_init_diff_val(int no_of_sems, int *array) - Inicia com um valor Problema IPC – Produtor Consumidor (Semáforos) Problema IPC – Produtor Consumidor (Semáforos) Problema IPC – Produtor Consumidor (Semáforos) Pipe • Método de conexão da saída de um processo com a entrada de outro processo. • Comunicação em só 1 sentido. (Half-Duplex) • Processos filhos herdam os File Descriptors dos seus processos pais. • Os processos devem fechar os File Descriptors que eles não vão usar. Pipe • Função: • int pipe(int[] fd); • Parâmetros: Um array de inteiros de tamanho 2. • Retorna: • 0 => Sucesso. • fd[0] = ID do File Descriptor de leitura. • fd[1] = ID do File Descriptor de escrita. • -1 => Falha. • EMFILE = Não há FDs livres ou a tabela de arquivos está cheia. • EFAULT = O array passado não é válido. Pipe – Substituindo entrada e saída padrões • Função: • int dup(int fd); • ID do FD => Sucesso • -1 => Falha • EBADF = FD passado não é válido. • EMFILE = Muitos descriptors para o processo. Memória Compartilhada • Um dos métodos mais simples de comunicação entre processos. • Os processos utilizam um espaço de endereço comum em memória. • Qualquer atualização realizada por um processo, pode ser visto por outro que compartilhe o mesmo segmento de memória. Memória Compartilhada • shmget(): - Através dessa função, pode-se criar ou ligar um segmento de memória compartilhada. - Retorno: : o identificador do segmento de memória compartilhada shmid ou, em caso de erro, retorna -1. Memória Compartilhada • key pode conter os seguintes valores: - IPC_PRIVATE (=0): indicando que a zona de memória não tem chave de acesso - o valor desejado para a chave de acesso do segmento de memória, utilizando a função ftok(). • size, é o tamanho em bytes do segmento de memória compartilhada. • shmflg permite a especificação dos direitos de acesso ao segmento de memória compartilhada, pode conter IPC_CREAT ou IPC_EXCL, que podem criar um novo segmento ou verificar se um dado segmento existe ou não. Memória Compartilhada • shmat(): - Antes que o processo possa utilizar um segmento de memória criado por outro processo, ele deve inicialmente se acoplar a esse segmento. E é essa função que liga o segmento de memória compartilhada, identificado por shmid, ao segmento de dados do processo que a chamou. - Retorno: identificador do segmento ou -1 em caso de erro. Memória Compartilhada • shmid é o identificador do segmento de memória compartilhada obtido a partir da chamada da função shmget(). • shmaddr especifica o endereço de acoplamento. - Se shmaddr é 0, o segmento é acoplado ao primeiro endereço possível determinado pelo sistema, que é o mais utilizado. - Se shmaddr não é 0, observa-se shmflg. Memória Compartilhada • shmctl(): - Permite realizar examinar modificações nosegmento compartilhado. - Retorno: 0 ou -1 em caso de erro. Memória Compartilhada • shmid: identificador do segmento de memória compartilhada. • cmd pode conter os seguintes valores: - IPC_RMID (0): O segmento de memória será destruído. O usuário deve ser o superusuário para realizar esta operação - IPC_SET (1): dá ao identificador do grupo, ao identificador do usuário, e aos direitos de acesso, os valores contidos no campo shm_perm da estrutura apontada por buf; a hora da modificação é também atualizada (membro shm_ctime); - IPC_STAT (2): é usada para copiar a informação sobre a memória compartilhada no buffer buf; Memória Compartilhada • shmdt() - Quando um processo não precisa mais de usar um segmento, deve desacoplar esse segmento do espaço de endereçamento do processo, para isso deve-se usar a função shmdt(), este segmento não poderá mais utilizado pelo processo após a chamada da função. - Retorno: 0 ou -1 em caso de erro. Memória Compartilhada • O único argumento shmaddr é o endereço obtido a partir de shmdt(). Referências • http://www.advancedlinuxprogramming.com/alp-folder/alp-ch05ipc.pdf • http://www.di.ubi.pt/~operativos/praticos/pdf/12-ipc.pdf • http://www.dca.ufrn.br/~adelardo/cursos/DCA409/node102.html • http://www.dicasl.com.br/arquivo/semaforos_kernel_memoria_compartilhada_e_cia.p hp