2010-11-15 8 views
2

J'essaie de passer des messages entre 2 threads en utilisant une file d'attente, mais je n'ai pas obtenu de résultats jusqu'à présent. Lorsque j'imprime le contenu du message après qu'il a été reçu et avant qu'il ne soit envoyé, il semble seulement garder sa valeur dans la bande de roulement. Je dois l'implémenter avec 1 thread de serveur et plusieurs threads de client, mais pour l'instant j'utilise seulement 1 de chaque. Voici mon codeC - Problème avec le passage de messages entre threads utilisant des files d'attente

struct msg        //struct for client requests to server 
{ 
     long mtype; 
     int numResources;   //number of resources to be requested 
     int ID;      //ID associated with client thread 
};           

int c1PID;        //process ID variable for client thread 1 
int serverPID; 

key_t key1; 
key_t keyS; 

int msqid1; 
int msqidS; 

int main(int arc, char *argv[]) 
{ 
     key1 = ftok(".", '1');  //queue for client thread 1 to receive msgs from server 
     msqid1 = msgget(key1, 666 | IPC_CREAT); 

     keyS = ftok(".", 's');       //general queue for server 
     msqidS = msgget(keyS, 666 | IPC_CREAT); 

     pthread_t threads[2];    //create an array of pthreads 

     if ((serverPID = pthread_create(&threads[0], NULL, server, NULL)) != 0) 
     { 
       perror("server thread"); 
       exit(1); 
     } 

     if ((c1PID = pthread_create(&threads[1], NULL, client, NULL)) != 0) 
     { 
       perror("client thread"); 
       exit(1); 
     } 

     pthread_exit(NULL); 
} 

void *server() 
{         
     struct msg request; 
     size_t size = sizeof(struct msg) - offsetof(struct msg, numResources); 

     while (1) 
     { 

       msgrcv(msqidS, &request, size, 2, 0); 

       printf("received: numResources requested = %d\n", request.numResources); 

       request.numResources = 9001; 

       printf("sending: numResources requested = %d\n", request.numResources); 

       msgsnd(msqid1, &request, size, 0); 

       sleep(1); 
     } 
} 

void *client() 
{ 
     struct msg request; 
     size_t size; 
     request.numResources = 0; 
     size = sizeof(struct msg) - offsetof(struct msg, numResources); 

     msgsnd(msqidS, &request, size, 0); 

     while(1) 
     { 
       msgrcv(msqid1, &request, size, 2, 0); 

       printf("received: numResources requested = %d\n", request.numResources); 

       request.numResources += 1;//(int)(ceil((double)(rand()%2)) + 1); 

       printf("sending: numResources requested = %d\n", request.numResources); 

       msgsnd(msqidS, &request, size, 0); 

       sleep(1); 
} 

J'ai pris beaucoup de mes déclarations d'impression, mais il ressemble à ceci:

Server thread: 
received: numResources = 9001; 
sending: numResources = 9001; 

client thread: 
received: numResources = 1; 
sending: numResources = 2; 

Server thread: 
received: numResources = 9001; 
sending: numResources = 9001; 

client thread: 
received: numResources = 2; 
sending: numResources = 3; 
+0

Essayez-vous d'implémenter un programme de serveur client qui sera sur deux machines distinctes ou allez-vous avoir deux threads qui se parlent? – JonVD

+0

Ils sont en train de se parler sur la même machine – Anon

Répondre

0

Edit: Le sizeof (struct msg) - offsetof (struct msg, numResources) ça devrait être bon.

Mais, votre mtype doit être, selon le docs, un nombre entier positif. Initialisez-le à 2, car vos appels à msgrecv indiquent de recevoir seulement le type de message 2.

Ajoutez la vérification d'erreur à tous les appels de msgsnd/msgrecv, ainsi vous êtes sûr que vous n'obtenez pas silencieusement des erreurs.

Ajoutez une vérification d'erreur à vos appels ftok et msgget.

+0

Je l'ai initialement compensée par numResources car un tutoriel de file d'attente que je suivais devait être compensé par le membre de données immédiatement après mtype. J'ai essayé de le changer en identification et cela n'a pas semblé faire n'importe quoi. – Anon

+0

En ce moment je passe en offsetof (struct msg, ID) comme paramètre de taille et toujours pas de chance:/Je vais essayer d'ajouter des messages d'erreur à l'envoi/réception – Anon

+0

Hmmm, j'ai mis en erreur attraper (si envoi/réception fonctions == -1, erreur d'impression et de sortie) et il a retourné "Argument invalide". Mais j'ai suivi mon guide tutoriel aussi étroitement que possible, je ne suis pas sûr que les arguments ne sont pas corrects. – Anon

1

Voici ce qui a été imprimé sur la course qui a semblé fonctionner.

program starting 
Msg sent from client 

*****In client thread***** 
Msg received by client 
received: numResources requested = 0 
sending: numResources requested = 1 
Msg sent from client 


*****In server thread***** 
Msg received by server 
received: numResources requested = 1 
sending: numResources requested = 9001 
Msg sent from server. 


*****In client thread***** 
Msg received by client 
received: numResources requested = 9001 
sending: numResources requested = 9002 
Msg sent from client 


*****In server thread***** 
Msg received by server 
received: numResources requested = 9002 
sending: numResources requested = 9001 
Msg sent from server. 


*****In client thread***** 
Msg received by client 
received: numResources requested = 9001 
sending: numResources requested = 9002 
Msg sent from client 


*****In server thread***** 
Msg received by server 
received: numResources requested = 9002 
sending: numResources requested = 9001 
Msg sent from server. 


*****In client thread***** 
Msg received by client 
received: numResources requested = 9001 
sending: numResources requested = 9002 
Msg sent from client 

Et immédiatement après ....

program starting 
Msg sent from client 

*****In client thread***** 
Msg received by client 
received: numResources requested = 9001 
sending: numResources requested = 9002 
Msg sent from client 


*****In server thread***** 
Msg received by server 
received: numResources requested = 0 
sending: numResources requested = 9001 
Msg sent from server. 


*****In client thread***** 
Msg received by client 
received: numResources requested = 9002 
sending: numResources requested = 9003 
Msg sent from client 


*****In server thread***** 
Msg received by server 
received: numResources requested = 9001 
sending: numResources requested = 9001 
Msg sent from server. 


*****In client thread***** 
Msg received by client 
received: numResources requested = 9003 
sending: numResources requested = 9004 
Msg sent from client 


*****In server thread***** 
Msg received by server 
received: numResources requested = 9001 
sending: numResources requested = 9001 
Msg sent from server. 

Ils ont été exécutés 1 après l'autre sans les modifications apportées au code entre les deux.

+0

Je l'ai couru à nouveau, et il m'a donné des nombres vraiment étranges les premières boucles, mais puis s'est reposé sur les résultats de la première itération où il a semblé fonctionner. Aucune idée .... EDIT: Ran une 4ème fois et ça me donne les résultats de la deuxième manche. Je vois un motif ... – Anon

2

Votre problème est que vous avez défini des autorisations non-sens sur vos files d'attente de messages. Dans ces lignes, vous avez utilisé une constante 666 où vous devriez avoir utilisé une octal constante 0666 décimales:

msqid1 = msgget(key1, 666 | IPC_CREAT); 
    msqid1 = msgget(key1, 666 | IPC_CREAT); 

Cela signifie que vous avez créé les files d'attente avec des autorisations octal , qui ne comprend pas l'autorisation de lecture - donc vos appels msgget() suivants échouent tous avec EPERM (que vous verrez si vous vérifiez ces appels pour les erreurs).

Vous devrez supprimer vos files d'attente de messages et autoriser votre programme à les recréer avec les autorisations appropriées. Vous devez utiliser le msqid pour la file d'attente avec la commande IPC_RMID-msgctl() pour ce faire, comme dans le programme suivant:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 

int main(int argc, char *argv[]) 
{ 
     if (argc < 2) { 
       fprintf(stderr, "Usage: %s <msqid> [<msgqid> ...]\n", argv[0]); 
       return 1; 
     } 

     while (*++argv) 
     { 
       int msqid = atoi(*argv); 

       printf("Removing msqid %d\n", msqid); 
       if (msgctl(msqid, IPC_RMID, NULL) != 0) { 
         perror("msgctl"); 
         return 2; 
       } 
     } 

     return 0; 
} 

En raison de la conception terrible des files d'attente de messages SYS V, vous ne pouvez pas obtenir le msqid valeurs de msgget() plus, car msgget() échoue. Pour obtenir les valeurs msqid à supprimer, recherchez dans le fichier /proc/sysvipc/msg.

PS:

Je recommande fortement d'utiliser des files d'attente de messages posix (mq_open(), mq_send(), mq_receive() etc.). L'interface est significativement améliorée.

Questions connexes