下面來(lái)說(shuō)說(shuō)如何用不用消息隊(duì)列來(lái)進(jìn)行進(jìn)程間的通信,消息隊(duì)列與命名管道有很多相似之處。有關(guān)命名管道的更多內(nèi)容可以參閱我的另一篇文章:Linux進(jìn)程間通信——使用命名管道
成都網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁(yè)設(shè)計(jì)、成都網(wǎng)站建設(shè)、微信開(kāi)發(fā)、成都小程序開(kāi)發(fā)、集團(tuán)成都企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。核心團(tuán)隊(duì)均擁有互聯(lián)網(wǎng)行業(yè)多年經(jīng)驗(yàn),服務(wù)眾多知名企業(yè)客戶;涵蓋的客戶類型包括:成都砂巖浮雕等眾多領(lǐng)域,積累了大量豐富的經(jīng)驗(yàn),同時(shí)也獲得了客戶的一致稱贊!
一、什么是消息隊(duì)列
消息隊(duì)列提供了一種從一個(gè)進(jìn)程向另一個(gè)進(jìn)程發(fā)送一個(gè)數(shù)據(jù)塊的方法。 每個(gè)數(shù)據(jù)塊都被認(rèn)為含有一個(gè)類型,接收進(jìn)程可以獨(dú)立地接收含有不同類型的數(shù)據(jù)結(jié)構(gòu)。我們可以通過(guò)發(fā)送消息來(lái)避免命名管道的同步和阻塞問(wèn)題。但是消息隊(duì)列與命名管道一樣,每個(gè)數(shù)據(jù)塊都有一個(gè)最大長(zhǎng)度的限制。
Linux用宏MSGMAX和MSGMNB來(lái)限制一條消息的最大長(zhǎng)度和一個(gè)隊(duì)列的最大長(zhǎng)度。
二、在Linux中使用消息隊(duì)列
Linux提供了一系列消息隊(duì)列的函數(shù)接口來(lái)讓我們方便地使用它來(lái)實(shí)現(xiàn)進(jìn)程間的通信。它的用法與其他兩個(gè)System V PIC機(jī)制,即信號(hào)量和共享內(nèi)存相似。
1、msgget函數(shù)
該函數(shù)用來(lái)創(chuàng)建和訪問(wèn)一個(gè)消息隊(duì)列。它的原型為:
int msgget(key_t, key, int msgflg);
與其他的IPC機(jī)制一樣,程序必須提供一個(gè)鍵來(lái)命名某個(gè)特定的消息隊(duì)列。msgflg是一個(gè)權(quán)限標(biāo)志,表示消息隊(duì)列的訪問(wèn)權(quán)限,它與文件的訪問(wèn)權(quán)限一樣。msgflg可以與IPC_CREAT做或操作,表示當(dāng)key所命名的消息隊(duì)列不存在時(shí)創(chuàng)建一個(gè)消息隊(duì)列,如果key所命名的消息隊(duì)列存在時(shí),IPC_CREAT標(biāo)志會(huì)被忽略,而只返回一個(gè)標(biāo)識(shí)符。
它返回一個(gè)以key命名的消息隊(duì)列的標(biāo)識(shí)符(非零整數(shù)),失敗時(shí)返回-1.
2、msgsnd函數(shù)
該函數(shù)用來(lái)把消息添加到消息隊(duì)列中。它的原型為:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函數(shù)返回的消息隊(duì)列標(biāo)識(shí)符。
msg_ptr是一個(gè)指向準(zhǔn)備發(fā)送消息的指針,但是消息的數(shù)據(jù)結(jié)構(gòu)卻有一定的要求,指針msg_ptr所指向的消息結(jié)構(gòu)一定要是以一個(gè)長(zhǎng)整型成員變量開(kāi)始的結(jié)構(gòu)體,接收函數(shù)將用這個(gè)成員來(lái)確定消息的類型。所以消息結(jié)構(gòu)要定義成這樣:
struct my_message{
long int message_type;
/* The data you wish to transfer*/
};
msg_sz是msg_ptr指向的消息的長(zhǎng)度,注意是消息的長(zhǎng)度,而不是整個(gè)結(jié)構(gòu)體的長(zhǎng)度,也就是說(shuō)msg_sz是不包括長(zhǎng)整型消息類型成員變量的長(zhǎng)度。
msgflg用于控制當(dāng)前消息隊(duì)列滿或隊(duì)列消息到達(dá)系統(tǒng)范圍的限制時(shí)將要發(fā)生的事情。
如果調(diào)用成功,消息數(shù)據(jù)的一分副本將被放到消息隊(duì)列中,并返回0,失敗時(shí)返回-1.
3、msgrcv函數(shù)
該函數(shù)用來(lái)從一個(gè)消息隊(duì)列獲取消息,它的原型為
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
msgid, msg_ptr, msg_st的作用也函數(shù)msgsnd函數(shù)的一樣。
msgtype可以實(shí)現(xiàn)一種簡(jiǎn)單的接收優(yōu)先級(jí)。如果msgtype為0,就獲取隊(duì)列中的第一個(gè)消息。如果它的值大于零,將獲取具有相同消息類型的第一個(gè)信息。如果它小于零,就獲取類型等于或小于msgtype的絕對(duì)值的第一個(gè)消息。
msgflg用于控制當(dāng)隊(duì)列中沒(méi)有相應(yīng)類型的消息可以接收時(shí)將發(fā)生的事情。
調(diào)用成功時(shí),該函數(shù)返回放到接收緩存區(qū)中的字節(jié)數(shù),消息被復(fù)制到由msg_ptr指向的用戶分配的緩存區(qū)中,然后刪除消息隊(duì)列中的對(duì)應(yīng)消息。失敗時(shí)返回-1.
4、msgctl函數(shù)
該函數(shù)用來(lái)控制消息隊(duì)列,它與共享內(nèi)存的shmctl函數(shù)相似,它的原型為:
int msgctl(int msgid, int command, struct msgid_ds *buf);
command是將要采取的動(dòng)作,它可以取3個(gè)值,
IPC_STAT:把msgid_ds結(jié)構(gòu)中的數(shù)據(jù)設(shè)置為消息隊(duì)列的當(dāng)前關(guān)聯(lián)值,即用消息隊(duì)列的當(dāng)前關(guān)聯(lián)值覆蓋msgid_ds的值。
IPC_SET:如果進(jìn)程有足夠的權(quán)限,就把消息列隊(duì)的當(dāng)前關(guān)聯(lián)值設(shè)置為msgid_ds結(jié)構(gòu)中給出的值
IPC_RMID:刪除消息隊(duì)列
buf是指向msgid_ds結(jié)構(gòu)的指針,它指向消息隊(duì)列模式和訪問(wèn)權(quán)限的結(jié)構(gòu)。msgid_ds結(jié)構(gòu)至少包括以下成員:
struct msgid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};
成功時(shí)返回0,失敗時(shí)返回-1.
三、使用消息隊(duì)列進(jìn)行進(jìn)程間通信
馬不停蹄,介紹完消息隊(duì)列的定義和可使用的接口之后,我們來(lái)看看它是怎么讓進(jìn)程進(jìn)行通信的。由于可以讓不相關(guān)的進(jìn)程進(jìn)行行通信,所以我們?cè)谶@里將會(huì)編寫(xiě)兩個(gè)程序,msgreceive和msgsned來(lái)表示接收和發(fā)送信息。根據(jù)正常的情況,我們?cè)试S兩個(gè)程序都可以創(chuàng)建消息,但只有接收者在接收完最后一個(gè)消息之后,它才把它刪除。
接收信息的程序源文件為msgreceive.c的源代碼為:
#include unistd.h
#include stdlib.h
#include stdio.h
#include string.h
#include errno.h
#include sys/msg.h
struct msg_st
{
long int msg_type;
char text[BUFSIZ];
};
int main()
{
int running = 1;
int msgid = -1;
struct msg_st data;
long int msgtype = 0; //注意1
//建立消息隊(duì)列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
//從隊(duì)列中獲取消息,直到遇到end消息為止
while(running)
{
if(msgrcv(msgid, (void*)data, BUFSIZ, msgtype, 0) == -1)
{
fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s\n",data.text);
//遇到end結(jié)束
if(strncmp(data.text, "end", 3) == 0)
running = 0;
}
//刪除消息隊(duì)列
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
發(fā)送信息的程序的源文件msgsend.c的源代碼為:
#include unistd.h
#include stdlib.h
#include stdio.h
#include string.h
#include sys/msg.h
#include errno.h
#define MAX_TEXT 512
struct msg_st
{
long int msg_type;
char text[MAX_TEXT];
};
int main()
{
int running = 1;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
//建立消息隊(duì)列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
//向消息隊(duì)列中寫(xiě)消息,直到寫(xiě)入end
while(running)
{
//輸入數(shù)據(jù)
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
data.msg_type = 1; //注意2
strcpy(data.text, buffer);
//向隊(duì)列發(fā)送數(shù)據(jù)
if(msgsnd(msgid, (void*)data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
//輸入end結(jié)束輸入
if(strncmp(buffer, "end", 3) == 0)
running = 0;
sleep(1);
}
exit(EXIT_SUCCESS);
}
轉(zhuǎn)載僅供參考,版權(quán)屬于原作者。祝你愉快,滿意請(qǐng)采納哦
public class Queue {
private LinkedListObject msgList = new LinkedListObject();
public Object getMsg() {
synchronized (this) {
if (msgList != null msgList.size() 0) {
return msgList.removeFirst();
}
return null;
}
}
public Object addMsg(Object obj) {
synchronized(this) {
msgList.addLast(obj);
}
return obj;
}
}
前幾天給別人寫(xiě)的,估計(jì)能實(shí)現(xiàn)你的要求的代碼,當(dāng)然沒(méi)寫(xiě)測(cè)試!
java中的消息隊(duì)列
消息隊(duì)列是線程間通訊的手段:
import java.util.*
public class MsgQueue{
private Vector queue = null;
public MsgQueue(){
queue = new Vector();
}
public synchronized void send(Object o)
{
queue.addElement(o);
}
public synchronized Object recv()
{
if(queue.size()==0)
return null;
Object o = queue.firstElement();
queue.removeElementAt(0);//or queue[0] = null can also work
return o;
}
}
因?yàn)閖ava中是locked by object的所以添加synchronized 就可以用于線程同步鎖定對(duì)象
可以作為多線程處理多任務(wù)的存放task的隊(duì)列。他的client包括封裝好的task類以及thread類
Java的多線程-線程間的通信2009-08-25 21:58
1. 線程的幾種狀態(tài)
線程有四種狀態(tài),任何一個(gè)線程肯定處于這四種狀態(tài)中的一種:
1) 產(chǎn)生(New):線程對(duì)象已經(jīng)產(chǎn)生,但尚未被啟動(dòng),所以無(wú)法執(zhí)行。如通過(guò)new產(chǎn)生了一個(gè)線程對(duì)象后沒(méi)對(duì)它調(diào)用start()函數(shù)之前。
2) 可執(zhí)行(Runnable):每個(gè)支持多線程的系統(tǒng)都有一個(gè)排程器,排程器會(huì)從線程池中選擇一個(gè)線程并啟動(dòng)它。當(dāng)一個(gè)線程處于可執(zhí)行狀態(tài)時(shí),表示它可能正處于線程池中等待排排程器啟動(dòng)它;也可能它已正在執(zhí)行。如執(zhí)行了一個(gè)線程對(duì)象的start()方法后,線程就處于可執(zhí)行狀態(tài),但顯而易見(jiàn)的是此時(shí)線程不一定正在執(zhí)行中。
3) 死亡(Dead):當(dāng)一個(gè)線程正常結(jié)束,它便處于死亡狀態(tài)。如一個(gè)線程的run()函數(shù)執(zhí)行完畢后線程就進(jìn)入死亡狀態(tài)。
4) 停滯(Blocked):當(dāng)一個(gè)線程處于停滯狀態(tài)時(shí),系統(tǒng)排程器就會(huì)忽略它,不對(duì)它進(jìn)行排程。當(dāng)處于停滯狀態(tài)的線程重新回到可執(zhí)行狀態(tài)時(shí),它有可能重新執(zhí)行。如通過(guò)對(duì)一個(gè)線程調(diào)用wait()函數(shù)后,線程就進(jìn)入停滯狀態(tài),只有當(dāng)兩次對(duì)該線程調(diào)用notify或notifyAll后它才能兩次回到可執(zhí)行狀態(tài)。
2. class Thread下的常用函數(shù)函數(shù)
2.1 suspend()、resume()
1) 通過(guò)suspend()函數(shù),可使線程進(jìn)入停滯狀態(tài)。通過(guò)suspend()使線程進(jìn)入停滯狀態(tài)后,除非收到resume()消息,否則該線程不會(huì)變回可執(zhí)行狀態(tài)。
2) 當(dāng)調(diào)用suspend()函數(shù)后,線程不會(huì)釋放它的“鎖標(biāo)志”。
例11:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i5; i++){
shareVar++;
if(shareVar==5){
this.suspend(); //(1)
}}}
else{
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.resume(); //(2)
}}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(5)
//t1.start(); //(3)
t2.start(); //(4)
}}
“消息隊(duì)列”是在消息的傳輸過(guò)程中保存消息的容器。和我們學(xué)過(guò)的LinkedHashMap,TreeSet等一樣,都是容器。既然是容器,就有有自己的特性,就像LinkedHashMap是以鍵值對(duì)存儲(chǔ)。存取順序不變。而消息隊(duì)列,看到隊(duì)列就可以知道。這個(gè)容器里面的消息是站好隊(duì)的,一般遵從先進(jìn)先出原則。
java中已經(jīng)為我們封裝好了很多的消息隊(duì)列。在java 1.5版本時(shí)推出的java.util.concurrent中有很多現(xiàn)成的隊(duì)列供我們使用。特性繁多,種類齊全。是你居家旅游開(kāi)發(fā)必備QAQ。
下面簡(jiǎn)單列舉這個(gè)包中的消息隊(duì)列
:阻塞隊(duì)列 BlockingQueue
數(shù)組阻塞隊(duì)列 ArrayBlockingQueue
延遲隊(duì)列 DelayQueue
鏈阻塞隊(duì)列 LinkedBlockingQueue
具有優(yōu)先級(jí)的阻塞隊(duì)列 PriorityBlockingQueue
同步隊(duì)列 SynchronousQueue
阻塞雙端隊(duì)列 BlockingDeque
鏈阻塞雙端隊(duì)列 LinkedBlockingDeque
不同的隊(duì)列不同的特性決定了隊(duì)列使用的時(shí)機(jī),感興趣的話你可以詳細(xì)了解。具體的使用方式我就不贅述了