Memória Partilhada Página 1 de 6 Memória Partilhada Pedaço de memória virtual que dois ou mais processos podem incluir no seu espaço de endereçamento, permitindo a comunicação entre eles. È o mecanismo mais rápido de comunicação entre processos (não existem trocas de dados entre os processos). É necessário garantir a sincronização no acesso à região de memória partilhada (para isso podem-se utilizar semáforos). Modo de Armazenamento As várias regiões de memória partilhada são armazenadas pelo kernel num local especial de memória - Region Table. O kernel mantém um array (Shared Memory Table) em que cada entrada possui informação referente ao nome, permissões e tamanho da região correspondente, assim como o apontador para a Region Table. Uma entrada no array shared memory table possui: nome da região; struct shmid_ds; { struct ipc_perm shm_perm; struct anon_map *shm_amp; ; /* apontador para o kernel */ int shm_segsz; /* Tamanho do segmento (em bytes) */ ushort shm_lpid; /* pid da última operação */ ushort shm_cpid; /* pid do criador */ ushort shm_nattach; /* nº de processos que fizeram shmat */ time_t shm_atime; /* hora do último shmat /* time_t shm_dtime; /* hora do último shmdt */ time_t shm_ctime; /* hora da última alteração de atributod da MP através de shmctl + IPC_SET */ } System Calls int shmget(int chave, int tamanho, int flags) - permite criar ou utilizar uma região de memória partilhada, de acordo com as flags flags. O identificador vai ser utilizado nas outras operações de memória partilhada. Parâmetro chave: 0 (IPC_PRIVATE) permite criar uma região de memória partilhada privada ao processo invocador; o idenficador resultante nunca vai ser retornado a outros processos que invoquem shmget (seja qual for o seu parâmetro chave); http://www.dei.isep.ipp.pt/~orlando/so2/memoria-partilhada.htm 10/9/2005 Memória Partilhada Página 2 de 6 o identificador pode ser partilhado com outros processos (ao serem efectuados sucessivos fork(), as variáveis do processo pai são herdadas pelas correspondentes variáveis dos processos filho); >0 permite criar ou abrir uma região de memória partilhada, de acordo com o conteúdo do parâmetro flags; a região de memória partilhada pode ser partilhada com qualquer outro processo, desde que o parâmetro chave seja igual. Parâmetro flags: Flag IPC_CREAT activa e IPC_EXCL activa cria a região de memória partilhada se a chave não existir (caso contrário retorna erro); permite verificar se uma dada região existe ou não. Flag IPC_CREAT e IPC_EXCL não activas retorna o identificador associado à região de memória partilhada chave (se chave existir, caso contrário retorna erro); se tamanho > tamanho_da_região então retorna erro. Flag IPC_CREAT activa e IPC_EXCL não activa cria a região de memória partilhada se chave não existir (se chave existe, retorna o identificador associado à região com essa chave); Nota: Ao fazer shmget de uma região de memória partilhada, devem ser respeitadas as permissões de acesso, isto é, as flags de permissão presentes no parâmetro flags (escritas na forma 0xxx), devem ser as mesmas da região de memória partilhada (aquando da sua criação). void *shmat(int shmid, void *shmaddr, int flags) - permite ligar a região de memória partilhada associada ao identificador shmid ao espaço virtual de endereçamento do processo invocador. Parâmetro shmaddr: identifica o endereço virtual (pertencente ao espaço de endereçamento do processo) onde deve ser feita a correspondência; 0 - o endereço é escolhido pelo sistema operativo; >0 - a correspondência é feita a partir do endereço especificado; Parâmetro flags permite escolher a permissão leitura/escrita ou somente de leitura. Nota 1: Ao executar um attach com sucesso, shm_nattach é incrementado 1 unidade; shm_lpid é associado ao pid do processo invocador e shm_atime é actualizado. http://www.dei.isep.ipp.pt/~orlando/so2/memoria-partilhada.htm 10/9/2005 Memória Partilhada Página 3 de 6 Nota 2: Existe um limite (estabelecido pelo sistema operativo) de segmentos partilhados por processo (o valor típico é 6) Nota 3: No caso da system call originar um erro, o valor retornado é -1, sendo associado à variável global errono o erro correspondente (caso contrário, retorna o endereço virtual inicial do espaço de endereçamento em que foi feito o shmat. int shmdt(void *shmaddr) - permite desligar uma região de memória partilhada do espaço de endereçamento virtual do processo invocador. O parâmetro shmaddr é o endereço virtual retornado por shmat. Nota: ao executar um dattach com sucesso, shm_nattach é decrementado 1 unidade, shm_lpid é associado ao pid do processo invocador e shm_dtime é actualizado. int shmctl(int shmid, int cmd, struct shmid_ds *buf) - permite alterar/consultar os atributos da região de memória partilhada identificada por shmid, ou destruir a região de memória partilhada. O comando cmd define se a operação vai ler/escrever atributos ou se vai destruir a região. Parâmetro cmd: IPC_STAT - retorna para o buffer apontado por buf a estrutura visível ao utilizador da região de memória partilhada - shmid_ds (o utilizador necessita de ter permissão de leitura); IPC_SET - são alterados os seguintes campos da região, para os valores encontrados em buf: shm_perm.uid, shm_perm.gid, shm_perm.mode e shm_ctime. O uid do processo invocador deve ser igual ao campo shm_perm.uid, ou igual ao campo shm_perm.cuid (ou deve ser o superuser); Se não ocorreu um erro o campo shm_ctime é actualizado. IPC_RMID - a região de memória partilhada é destruída, isto é, é removida da Region Table, assim como também é removido o identificador da shared memory table. a região só é removida quando todos os processos que estiverem ligados a ela (shmat) se desligarem (shmdt). De qualquer modo, a partir do momento em que é invocado shmctl + IPC_RMID, mais nenhum processo consegue fazer o shmat dessa região; o uid do processo invocador deve ser igual ao campo shm_perm.uid, ou igual ao campo shm_perm.cuid (ou então deve ser o superuser). Exemplo Escritor.c - este programa escreve um número na região de memória partilhada #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> http://www.dei.isep.ipp.pt/~orlando/so2/memoria-partilhada.htm 10/9/2005 Memória Partilhada Página 4 de 6 #include <sys/shm.h> main() { void *memoria_partilhada = (void *) 0; /* apontador para o segmento de memoria partilhada */ int *aponta; int shmid; int valor; /* cria ou utiliza o segmento de memória partilhada - neste caso cria uma região com o tamanho de um inteiro */ shmid = shmget((key_t)1245, sizeof(int), 0666|IPC_CREAT); if (shmid == -1) { printf("Erro !!!\n"); exit(-1); } /* "Ligação" 'a região de memória partilhada */ memoria_partilhada = shmat(shmid, (void *)0,0); if (memoria_partilhada == (void *) -1) { printf("Erro ao fazer shmat\n"); exit(-1); } printf("A memoria esta' 'ligada' em %X\n", (int)memoria_partilhada); aponta = (int *) memoria_partilhada; printf("Valor: "); scanf("%d",&valor); /* altera o valor da região de memória partilhada */ *aponta=valor; /* "Desliga-se" da região de memória partilhada */ http://www.dei.isep.ipp.pt/~orlando/so2/memoria-partilhada.htm 10/9/2005 Memória Partilhada Página 5 de 6 if (shmdt(memoria_partilhada) == -1) { printf("Erro ao fazer shmdt\n"); exit(-1); } } Leitor.c - este programa lê um número da região de memória partilhada #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> main() { void *memoria_partilhada = (void *) 0; /* apontador para o segmento de memoria partilhada */ int *aponta; int shmid; /* cria ou utiliza o segmento de memória partilhada */ shmid = shmget((key_t)1245, sizeof(int), 0666|IPC_CREAT); if (shmid == -1) { printf("Erro !!!\n"); exit(-1); } memoria_partilhada = shmat(shmid, (void *)0,0); if (memoria_partilhada == (void *) -1) { http://www.dei.isep.ipp.pt/~orlando/so2/memoria-partilhada.htm 10/9/2005 Memória Partilhada Página 6 de 6 printf("Erro ao fazer shmat\n"); exit(-1); } printf("A memoria esta' 'ligada' em %X\n", (int)memoria_partilhada); aponta = (int *) memoria_partilhada; printf("O valor que esta' na regiao de memoria partilhada e' %d\n", *aponta); /* "Desliga-se" da região de memória partilhada */ if (shmdt(memoria_partilhada) == -1) { printf("Erro ao fazer shmdt\n"); exit(-1); } /* para remover a região de memória partilhada, tire o de comentário as seguintes linhas */ /* if (shmctl(shmid, IPC_RMID, 0) == -1) { printf("Erro ao remover a regiao de memoria partilhada\n"); exit(-1); } */ } http://www.dei.isep.ipp.pt/~orlando/so2/memoria-partilhada.htm 10/9/2005