2010-11-15 25 views
2

我想使用一個隊列在2個線程之間傳遞消息,但到目前爲止我還沒有得到任何結果。當我收到消息並在發送消息之前打印消息的內容時,它似乎只是保持其值。我需要用1個服務器線程和多個客戶端線程來實現它,但現在我只使用每個線程中的一個。這裏是我的代碼C - 在使用隊列的線程之間傳遞消息的問題

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); 
} 

我拿出我的很多的print語句,但它看起來是這樣的:

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

您是否試圖實現一個客戶端服務器程序,它將在兩臺獨立的機器上運行,或者您將只有兩個線程相互通信? – JonVD 2010-11-15 01:31:55

+0

他們只是在同一臺機器上互相交談 – Anon 2010-11-15 01:34:34

回答

0

編輯: 的的sizeof(結構MSG) - offsetof(結構味精,numResources );應該可以。

但是,根據docs,您的mtype需要爲正整數。將它初始化爲2,因爲你對msgrecv的呼叫表示只接收消息類型2.

向所有的msgsnd/msgrecv調用添加錯誤檢查,所以你確定你沒有默默得到錯誤。

將錯誤檢查添加到您的ftok和msgget調用中。

+0

我最初通過numResources來抵消它,因爲我之前所說的隊列教程說,在mtype之後立即由數據成員抵消。我嘗試將其更改爲ID,但似乎沒有做任何事情。 – Anon 2010-11-15 01:37:13

+0

現在我通過offsetof(結構體味,ID)作爲大小參數,仍然沒有運氣:/我會嘗試添加錯誤消息發送/接收 – Anon 2010-11-15 01:48:03

+0

嗯,我把錯誤捕捉(如果發送/接收函數== -1,打印錯誤並退出),並返回「無效參數」。但是我儘可能接近我的教程指南,我不確定哪些論點是不正確的。 – Anon 2010-11-15 02:03:11

1

以下是運行時顯示的工作狀態。

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 

緊接着又....

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. 

這些都沒有在這兩者之間的代碼所做的更改運行後,其他1。

+0

我再次運行它,它在前幾個循環中給了我非常奇怪的數字,但後來解決了第一次迭代中似乎正在工作的結果。不知道.... 編輯:運行它第四次,它給我第二次運行的結果。我看到一種模式... – Anon 2010-11-15 02:21:30

2

你的問題是你已經在消息隊列上設置了無意義的權限。在這些線路,你已經使用十進制常量666,你應該用一個八進制常數0666

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

這意味着,您所創建的隊列,八進制權限,不包括讀權限 - 所以你的後續msgget()調用現在都失敗EPERM(你會看到,如果你檢查這些呼叫的錯誤)。

您必須刪除消息隊列,並允許程序使用正確的權限重新創建消息隊列。你需要與IPC_RMID命令使用msqid的隊列msgctl()要做到這一點,如下面的程序:

#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; 
} 

由於SYS V消息隊列的可怕的設計,你不能得到msqid因爲msgget()失敗,所以從msgget()開始的值。要獲取要刪除的msqid值,請查看文件/proc/sysvipc/msg

PS:

強烈建議使用POSIX消息隊列代替(mq_open()mq_send()mq_receive()等)。界面顯着改善。