troca de mensagens - IME – Instituto de Matemática e Estatística
Transcrição
troca de mensagens - IME – Instituto de Matemática e Estatística
Página 1 de 5 INSTITUTO SUPERIOR DE CIÊNCIAS DO TRABALHO E DA EMPRESA Sistemas Operativos 2º Semestre 2003/2004 ETI - IGE Aula 04 Filas de mensagem 1. Criar uma fila de mensagens. Mandar uma mensagem. Os procedimentos para filas de mensagens são em parte semelhantes aos dos semáforos. Para criar uma fila de mensagens usase a função msgget, como se exemplifica no seguinte programa que também envia uma mensagem para a fila criada. Para enviar uma mensagem usa-se a função msgsnd. O primeiro argumento é, obviamente, o id obtido de msgget. O segundo argumento é a mensagem propriamente dita, o terceiro argumento é o tamanho da mensagem e o último argumento é, normalmente, 0 (mas adiante veremos outras hipóteses). Sobre a mensagem, a regra é que deve existir um campo int (designado de "tipo" da mensagem) antes da mensagem propriamente dita. Dentro desta regra, é o programa que define a estrutura das mensagens. Neste caso foi definida uma estrutura MsgStruct que prevê mensagens contendo, no máximo, 250 caracteres. #include <stdio.h> #include <sys/ipc.h> #include <sys/msg.h> typedef struct { int type; char text[250]; } MsgStruct; main() { int msg_id; int status; MsgStruct msg; // ligar à fila de mensagens msg_id = msgget ( 1000, 0600 | IPC_CREAT ); exit_on_error (msg_id, "Criação/Ligação"); // enviar ums mensagem msg.type = 1; strcpy( msg.text, "Uma mensagem qualquer."); status = msgsnd( msg_id, &msg, sizeof(msg.text), 0); exit_on_error (msg_id, "Envio"); printf ("Mensagem enviada!\n"); } 2. Comandos O comando ipcs -m (ou só ipcs) permite ver as filas de mensagens criadas. Pode também, nessa lista, ver o número de mensagens actualmente em espera na fila. 3. Receber uma mensagem. O seguinte programa recebe (receber, neste contexto, quer dizer retirar) uma mensagem da fila. A única diferença sensível é que, file://C:\DOCUME~1\THIAGO~1\CONFIG~1\Temp\VOM29K58.htm 5/9/2005 Página 2 de 5 em vez de msgsnd para mandar uma mensagem, temos a função msgrcv para receber. Nesta chamada o primeiro, segundo e terceiro argumentos têm significados idênticos ao de mandar. O segundo indica a estrutura que vai receber a mensagem e o terceiro indica a dimensão dessa estrutura. O quarto argumento indica o tipo de mensagem que se pretende receber. O programa só vai receber mensagens do tipo indicado, neste caso do tipo 1 (ou seja, se houver na fila mensagens de outro tipo, para este efeito, é como se não existissem). Felizmente que o programa anterior mandou a mensagem como sendo do tipo 1! Finalmente, o último argumento continua em 0. Isto faz com que, se não houver uma mensagem disponível na fila (que seja do tipo 1) o programa ficará bloqueado em espera; só desbloqueará quando alguém enviar uma nova mensagem (do tipo 1) para a fila. #include #include #include #include <stdio.h> <sys/ipc.h> <sys/msg.h> "my_include.h" typedef struct { int type; char text[250]; } MsgStruct; main() { int msg_id; int status; MsgStruct msg; // ligar à fila de mensagens msg_id = msgget ( 1000, 0600 | IPC_CREAT ); exit_on_error (msg_id, "Criação/Ligação"); // receber uma mensagem (bloqueia se não houver) status = msgrcv( msg_id, &msg, sizeof(msg.text), 1, 0); exit_on_error (msg_id, "Recepção"); printf ("MENSAGEM <%s>\n", msg.text); } 4. No wait Experimente os programas anteriores com diferentes sequências; por ex: com o primeiro põe várias mensagens na fila; com o segundo tirar cada um delas. Evidentemente, o segundo programa só bloqueia se, no momento, não houver qualquer mensagem disponível. Em alternativa, o último argumento do msgrcv pode ser IPC_NOWAIT. Neste caso o msgrcv não bloqueia. Vai buscar uma mensagem e se houver recolhe senão segue à sua vida. 5. Exemplo: cliente / servidor O exemplo seguinte implementa um modelo em que um ou mais clientes mandam mensagens para um servidor, que responde a cada um deles. A estrutura da mensagem é agora maios elaborada. Além da parte obrigatória (ou seja, o "tipo" da mensagem) a mensagem tem agora dois campos: um identificador que irá conter o número do processo que envia a mensagem e o texto da mensagem, propriamente dito. O esquema é o seguinte: file://C:\DOCUME~1\THIAGO~1\CONFIG~1\Temp\VOM29K58.htm 5/9/2005 Página 3 de 5 - o servidor só procura na fila mensagens do tipo 1; o cliente manda para o servidor uma mensagem do tipo 1, indicando o seu pid no corpo da mensagem; o servidor responde com uma mensagem com tipo igual ao pid indicado pelo cliente; em conformidade, o cliente, procura na fila de mensagens uma resposta com tipo igual ao seu próprio pid; file://C:\DOCUME~1\THIAGO~1\CONFIG~1\Temp\VOM29K58.htm 5/9/2005 Página 4 de 5 SERVIDOR #include <stdio.h> #include <sys/ipc.h> #include <sys/msg.h> typedef struct { int type; struct _msg_struct { int pid; char text[250]; } msg; } MsgStruct; main() { int msg_id; int status; MsgStruct msg; int premio = 0; // ligar à fila de mensagens msg_id = msgget ( 1000, 0600 | IPC_CREAT ); exit_on_error (msg_id, "Criação/Ligação"); // receber uma mensagem (bloqueia se não houver) while (1 ) { status = msgrcv( msg_id, &msg, sizeof(msg.msg), 1, 0); exit_on_error (msg_id, "Recepção"); printf ("DE PID %d: <%s>\n", msg.msg.pid, msg.msg.text); msg.type = msg.msg.pid; if ( ++premio %5 == 0 ) { strcpy ( msg.msg.text, "PREMIO!" ); printf ("Premio para PID =%d\n", msg.msg.pid); } else strcpy ( msg.msg.text, "Tente de novo." ); status = msgsnd( msg_id, &msg, sizeof(msg.msg), 0); exit_on_error (msg_id, "Resposta"); } } file://C:\DOCUME~1\THIAGO~1\CONFIG~1\Temp\VOM29K58.htm 5/9/2005 Página 5 de 5 CLIENTE #include #include #include #include <stdio.h> <sys/ipc.h> <sys/msg.h> "my_include.h" typedef struct { int type; struct _msg_struct { int pid; char text[250]; } msg; } MsgStruct; main() { int msg_id; int status; MsgStruct msg; char s[250]; // ligar à fila de mensagens msg_id = msgget ( 1000, 0600 | IPC_CREAT ); exit_on_error (msg_id, "Criação/Ligação"); printf ("PID=%d\n", getpid()); while ( 1 ) { msg.type = 1; msg.msg.pid = getpid(); printf("Mensagem: "); gets(s); strcpy( msg.msg.text, s ); status = msgsnd( msg_id, &msg, sizeof(msg.msg), 0); exit_on_error (msg_id, "Envio"); status = msgrcv( msg_id, &msg, sizeof(msg.msg), getpid(), 0); exit_on_error (msg_id, "Resposta"); printf ("Resposta: %s\n", msg.msg.text ); } } file://C:\DOCUME~1\THIAGO~1\CONFIG~1\Temp\VOM29K58.htm 5/9/2005