1ª Avaliação Faculdades Integradas de Caratinga Sistemas Distribuídos Jacson RC Silva Exercícios Avaliativos Memória Compartilhada Uma posição de memória compartilhada é identificada por uma chave. Essa chave pode ser IPC_PRIVATE para que somente o pai e seus filhos consigam acessar, ou pode ser um número para que vários processos diferentes consigam acessar. Encontramos um problema nessa implementação: se um outro processo souber minha chave, ou se ele coincidentemente colocar minha chave, ele conseguirá acessar minha posição de memória, o que causará muitos erros. Para isso, torna-se necessário a utilização da função ftok(). Ela cria uma chave através do nome do seu programa e de um número que você passe. 1. Execute o código abaixo e descreva o que você entendeu. // armazenamento da chave int i; // para utilizarmos todos os valores possíveis // de chaves para um pathname for ( i=0 ; i<=255 ; i++ ) // syntaxe: key_t ftok ( char *pathname, char proj ) chave = ftok ( argv[0], i ); if (chave == -1) perror("erro ao criar a chave"); else printf("valor da chave: %#x\n", chave); 2. Troque o número 255 para um número maior e indique o que aconteceu Para que a chave não fique vinculada somente ao nome do seu programa ( argv[0] ), podemos utilizar um outro nome de arquivo. 3. Modifique o valor de argv[0] para outro_nome.chave. Depois, compile e execute novamente seu programa. O que aconteceu? Qual o erro informado? (obs: o perror serve para escrever na tela o erro retornado pela função de sistema chamada, no nosso caso, o ftok() ) 4. Bom, agora simplesmente crie um arquivo com o nome outro_nome.chave na pasta do seu programa e execute-o novamente. O erro aconteceu novamente? Por que?
Agora que já aprendemos a criar chaves, vamos aprender a criar e utilizar memórias compartilhadas. A memória compartilhada é uma posição de memória alocada pelo sistema operacional e identificada por uma ID. A função que pede ao sistema operacional para criar a chave chama-se shmget(). Esta função que será responsável por alocar uma posição de memória e retornar seu ID. Vamos criar uma posição de memória: 1. Execute o programa abaixo e dê o comando ipcs -m. Por que sua memória não apareceu? typedef struct valores; if (chave == -1) perror("erro ao criar a chave"); exit(1); if (mem_id == -1) perror("erro ao criar memoria");exit(2); 2. Será que ela não foi criada? Bom, mudando um pouco de pau pra cavaco, para um outro programa utilizar essa memória criada, ele tem que utilizar a mesma chave e a mesma função do programa que acabamos de fazer, ou seja, seu início deve ser idêntico ao que fizemos. Para garantir que a posição de memória é do seu programa, ou seja, que já não existia na memória uma outra posição com a chave que você utilizou, temos que adicionar a diretiva IPC_EXCL. Faça isso e execute novamente seu programa, basta alterar IPC_CREAT por IPC_CREAT IPC_EXCL. Execute novamente seu programa. Qual o erro apresentado? O erro File Exists quando relacionado a memória, significa que essa posição já existe. 3. Bom, já que vimos que ela existe, vamos agora trabalhar com sua permissão. Vamos dar permissão ao dono (usuário que criou) de leitura e escrita. Faça os passos: remova a memória com o comando: ipcrm -m ID_QUE_SEU_PROGRAMA_ESCREVEU Adicione o include: #include <sys/stat.h> Modifique
de: IPC_CREAT IPC_EXCL para: IPC_CREAT IPC_EXCL S_IRUSR S_IWUSR Execute novamente o programa e verifique a memória criada com o comando ipcs 3. Agora, encontre e sua memória dentre os segmentos listados pelo ipcs e responda: qual a relação entre a sua chave e a memória criada? qual a relação entre a sua ID e a memória criada? qual a relação de permissão entre seu usuário e a memória criada? 4. Agora vamos escrever valores em nossa memória. Execute o programa abaixo e faça outro programa para ler essas informações e escrevê-las na tela: #include <string.h> typedef struct valores; // acesso a nossa memória valores *minhamemoria; if (chave == -1) perror("erro ao criar a chave"); exit(1); if (mem_id == -1) perror("erro ao criar memoria");exit(2); minhamemoria = (valores*) shmat(mem_id, NULL, NULL); if ( ((int) minhamemoria) == -1 ) perror("erro ao obter endereço da mem");exit(3); printf("colocando na memória o nome \"Jeiks\"\n"); strcpy( minhamemoria->nome, "Jeiks" ); printf("colocando na memória a idade 25\n"); minhamemoria->idade = 25; printf("desassociando da memória\n"); if ( shmdt( minhamemoria ) == -1 ) perror("erro no shmdt()");exit(3);
Agora temos que apagar a memória através de nosso programa, pois é feio sempre utilizar o ipcrm. [ ;) ] 5. Compile e execute o programa abaixo e descreva seu funcionamento. #include <string.h> typedef struct valores; if (chave == -1) perror("erro ao criar a chave"); exit(1); if (mem_id == -1) perror("erro ao criar memoria");exit(2); // syntaxe: // int shmctl(int shmid, int cmd, struct shmid_ds *buf); if ( shmctl( mem_id, IPC_RMID, NULL) == -1 ) perror("erro ao destruir a memória"); exit(3); printf("memória removida\n"); Como vocês puderam notar, podemos ter vários programas diferentes: um para criar a memória; outro para colocar os valores; outro para ler os valores; e outro para remover a memória. A implementação é bem livre para o usuário, para assim ele conseguir utilizar esse sistema de memórias compartilhadas à vontade. 6. Como último exercício de memória compartilhada, crie um semáforo para garantir o acesso a memória como seção crítica. Para isso, faça: crie um semáforo; antes de entrar na seção crítica, chame a função shm_wait(); após utilizar a seção crítica, chame a função shm_post().
As filas de mensagens seguem os mesmos conceitos da memória compartilhada. Com esses conceitos, obtenha o arquivo fila_mensagens.zip, compile e execute os arquivos que ele contém e descreva como utilizar uma fila de mensagens.