Semáforos Os semáforos são objetos IPC utilizados para sincronização entre processos. São mecanismo para resolver problemas de exclusão mútua. Comando do IPC: ipcs - ipcs -m ; informações relativas aos segmentos de memória compartilhada. ipcs -s ; informações sobre semáforos. ipcs -q ; informações sobre as filas de mensagens. ipcs -a ; informações sobre todos os recursos. ipcrm [sem|shm|msg] ; destrui recurso (semáforo, memória compartilhada ou mensagem identificado por . ipcrm msg 2344 Funcionamento de um Semáforo: - É uma variável (sem_var) inteira não negativa. - Há duas operações atômicas permitidas: P e V. - P(sem_var). Se sem_var é maior que zero, decrementa sem_var de 1. Se sem_var é zero, suspende a execução do processo que chamou a função P(sem_var), colocando-o numa fila FIFO de espera. - V(sem_var). Se há algum processo na fila de espera, retire o primeiro. Se não nenhum processo na fila de espera, incremente sem_var de 1. Implementação de Semáforos de Dijsktra: - Cada semáforo está associado a um identificador único (descritor), que no caso é um número inteiro positivo. - Criar um semáforo significa alocar um recurso e associá-lo a um destritor único no sistema. - Destruir um semáforo significa liberar os recursos e o destritor associado, sendo que só o criador do semáforo ou o super-usuário podem destrui-lo. Procedimento de Utilização de Semáforo: semaforo_1 = criacao_de_semaforo(valor_inicial); ... P(semaforo_1); // entrada na região crítica Regiao_critica; V(semaforo_1); Regiao_nao_critica; // saída da região crítica ... descruicao_de_semaforo(semaforo_1); Função de Criação de Semáforos em Unix: #include #include // quase sempre utilizada #include // quase sempre utilizada int semget(key_t key, int num_sems, int sem_flags); - Cria um novo conjunto de semáforos ou obtém a chave (key) de um já existente. - Valor de retorno: descritor do conjunto de semáforos ou -1 em caso de erro. - key: é um inteiro utilizado para permitir que processos não correlacionados acessem o mesmo semáforo. - key é somente utilizado com a função semget, todas as outras funções de semáforo utilizam o valor retornado por semget como identificador do semáforo. - num_sems: define o número de semáforos a serem criados. Usualmente este valor é igual a 1. - sem_flags: cunjunto de flags que especifica os direito de acesso ao conjuto de semaforos. - Se key for IPC_PRIVATE (=0), cria-se um novo cunjunto de semáforo, no caso, privados. - Se o número especificado por key ainda não foi utilizado e IPC_CREAT for colocado em semflag, é criado um novo conjunto de semáforos. - O argumento semflag é definido como uma combinação de diferentes constantes pré-definidas, permitindo a especificação de direitos de acesso. Segue a definição de permições de arquivos: rwx,rwx,rwx: user,group,all: 421,421:421. Por exemplo, 666: user, group e all podem ler e escrever. -> As constantes utilizadas com semflag pré-definidas em e em são as seguintes: #define IPC_CREAT 01000 // Cria chave se ela ainda não existe #define IPC_EXCL 02000 // Falha se a chave já existe #define IPC_NOWAIT 04000 // Retorna um erro no wait -> Criando um Semáforo 1- key deve conter um valor identificando um conjunto de semáforos (diferente de IPC_PRIVATE=0); 2- semflag deve conter os direitos de acesso desejados para o semáforo, e a constante IPC_CREATE; 3- Se deseja-se testar a existência de um conjunto correspondente a uma chave key determinada, deve-se adicionar (usando-se o operador OU lógico) ao argumento semflag a constante IPC_EXCL. A chamada da função semget() irá falhar no caso da existência de um conjunto de semáforos associado à chave key. - Execute o programa semaforo1.cpp. - Execute o comando ipcs -s - Execute novamente o programa semaforo1 e analise a resposta - Execute o comando ipcrm -s para remover o conjunto de semárofos - Em semaforo1.cpp, altere o valor de semflag e analise os resultados. Função de Operação de Semáforos em Unix #include #include #include int semop (int sem_id, struct sembuf *sem_ops, size_t num_sem_ops); - Função atômica que retorna o valor do último semáforo manipulado ou -1 em caso de erro. - sem_id é o descritor do conjunto de semáforos, obtido como retorno de semget(). - sem_ops é um ponteiro para um array de estruturas (cada estrutura indica uma operação que será realizado no conjunto indicado por sem_id), sendo que cada uma delas deverá ter no mínimo os seguintes membros: struct sembuf { short sem_num; // número do semárofo, usualmente 0 (semáforo escalar) short sem_op; // valor pelo o qual o semáforo deverá ser incrementado. Usualmente: -1 e +1 short sem_flg; // usualmente se utiliza SEM_UNDO } - num_sem_ops indica o tamanho do array sem_ops: número de operação a serem realizadas no conjunto de semáforos indicado por sem_id. Função de Controle de Informação de Semáforos em Unix #include #include #include int semctl(int sem_id, int sem_num, int cmd, union semun arg) - sem_id é o identificador do semáforo. - sem_num é o número do semáforo, tipicamente igual a 0 (semáforo escalar) - União arg: deve conter pelo menos os seguintes membros: union semun { int val; struct semid_ds *buf; unsigned short *array; } - cmd - há vários comando possíveis. Os fundamentais são: -> SETVAL: usado para inicializar um semáforo com um valor conhecido. Valor é passado através da variável val na união arg. Isto é requerido para setar o semáforo antes dele ser utilizado pela primeira vez. -> IPC_RMID: É utilizado para deletar um identificador de semáforo quando ele não é mais necessário. Um Classe Simples Para Operar Semáforos de Dijsktra - Ver classe Class_sem.cpp - Construtor: cria e inicializa semáforo - Destrutor: libera recursos alocados pelo semáforo - P(): Operação de entrada - V(): Operaçào de liberação