邮箱与消息队列有什么联系和区别?

时间:2022-08-27 18:51:00
如题,请着重说出邮箱的原理,机制,还有它与消息队列的区别,谢谢!

30 个解决方案

#1


阅读下 linux源码即可

#2


邮箱是个比喻,就是说有人往里放东西,有人把东西拿出来用。
这个跟消息队列很相似,消息队列就是一个task向队列里放消息,一个task从队列里拿消息。就是一个类比而已!

#3


什么书上的比喻,其实你只要知道消息是用队列存储的就可以了,其他的不必知道

#4


UP

#5


up

#6


形式上的相似吧,其它嘛……暂时不清楚,毕竟邮箱是一个完整的系统。

#7


up

#8


邮箱用于大数据的传送.
队列多用于处理有序的事件.


消息队列又是未必先进先出

#9


邮箱是一个通过在系统共享存储区内传递消息来实现同步和通信的对象。
每个邮箱包含一个用于发送消息的消息队列和一个用来接受消息的消息队列。由于是在共享存储区域,因此它对每个任务都是可见的。

而一般的消息队列,还可用来处理任务与外部事件之间的通信。比如一个按键消息。然后其中一个任务可以在消息队列中尝试去获取消息。消息的分发可以由一个线程对立进行,或是通过事件处理例程进行发派。

总的来说,邮箱的空间开销比一般的消息队列要大(每个邮箱包含两个消息队列),不过由于是共享的,因此任务之间的消息同步可以通过邮箱进行。而传统的消息队列除了在任务之间进行消息传递之外,还可以让事件处理例程进行消息发派。每个任务可以有一个私有的消息队列,然后该任务可以通过将自己队列的地址进行注册,告诉给系统;或者传递给其它任务。另外,传统的消息队列中的消息的长度可以是不定长的。而由于邮箱定义在全局共享区,一般每个邮箱的大小及规格是固定的。

它们的共同点是,如果某个任务去接受消息,但失败,那么它就会处于等待状态。这时也可以结合事件进行唤醒触发,不过系统或另一个任务向它发送消息后会自动将其唤醒。

#10


消息队列,习惯用管道来比喻
邮箱就管道中几个数据同时移动。

#12


up星羽GG

#13


邮箱 
服务器上是 一些文件,比如收件箱 ,发件箱 
用户的 目录 可能用hash算法 来得到,
当然每个用户只对自己的 目录有读写权限.......

#14


两者有联系

#15


我认为zenny_chen的分析是比较符合我的要求。

1. 那我是不是可以理解为:邮箱是工作在共享内存区的一种特殊的消息队列?
我对消息队列是比较熟悉的,但不太了解邮箱的工作机制。
2. 邮箱在数据结构组织上,是不是也是一个队列?谢谢。

#16


对,你这样理解也没问题。邮箱在数据结构上是一个双队列。一端由发送方发送消息,然后由系统在某一时刻将发送队列中的消息移入接收消息队列。
这就好比你写封信给你的一个朋友,你先是把信塞进邮筒,然后由邮局将邮筒的信件做统一批处理,最后分发给每户人家。这里其实也差不多,只不过这里没有邮递员和邮局的处理,而是发送者直接将信件发送到接收者家的邮箱中。

对于一份邮件,它包含了消息ID,发送者以及接收者(就像你写信,要写发信人和收信人地址一样)以及消息内容(通常是一个void*指针)。在你投信出去时,系统可能并不会马上将发送的的信转到接收队列,而且发送方一次可以发多个信件,因此这个动作可能在特定事件下,如:调度、定时器超时等,或者是在DSR(延迟的中断服务例程)中进行处理。
然后接收者就可以在指定的邮箱中等待接收信件了。

像楼上的xiaopoy(10楼)和xxgamexx(8楼)都说的不错。邮箱的特点是可以批传输消息,也就是说一次可以发多份消息,或者是在很短的时间间隔内连续发送消息。对于某些需要批消息处理的可以使用邮箱机制。

这里举个例子,比如说我们在玩PC时会有几个按键同时按下的情况(如:Alt+Delete+Ctrl)。这时可以利用邮箱来判断在某段时间内,有哪几个按键被同时按下。当按键扫描线程在扫到一个按键被按下时,立即将它放入邮箱,然后再扫,直到这段时间片被用完,系统将这些键值全都放入到邮箱的接收消息队列。然后在应用程序端可以通过邮箱接收到0个或多个键值的组合来作出不同的事件处理。

#17


一般邮箱可能被做成单工的,也就是说对于一个邮箱,发送者不能逆转为接收者。然后,发送者和接收者都知道所创建邮箱的地址。

而对于消息队列,它的伸缩性比邮箱更强,可以做成各种形式的。对于一个消息一定有消息接收者的地址,系统将某个消息发送给接收者时,如果此时接收者处于阻塞状态,那么可以将其唤醒。而邮箱一般不是通过单个消息将接收者唤醒的,而是邮箱本身,即当系统将某个邮箱的发送队列中的消息送往接收队列之后,做唤醒操作。所以从实时性上看,消息队列应该比邮箱反应更快。不过,邮箱却可以捕获更多的实时内容。因为做一次唤醒,然后任务切换的消耗可能是比较大的。

#18


zenny_chen 回答好详细啊~~

#19


对于邮箱的发送消息队列和接收消息队列,应该怎么理解?
比如:进程A有一个邮箱a,a的发送消息队列是1,接收消息队列是2;
同理,进程B有一个邮箱b,b的发送消息队列是11,接收消息队列是22;

比如:进程A要发送一个消息M给进程B,那么这两个邮箱的消息队列是怎么样的处理过程?也就是说,消息M如何在这些队列中传递?谢谢!

#20


从嵌入式系统uc/os来说,邮箱跟消息队列在实现上是没有区别的,邮箱相当于只可以存放一条消息的消息队列,一般来说邮箱用于紧急任务,而消息队列用于平常的任务,所以邮箱里只放一条消息,因为一有消息立马就能得到处理,系统根本就没有机会往同一个邮箱里再存一条消息,所以从邮箱里取消息的任务都是非常高优先级的。

#21


嗯。对于不同的操作系统可能一些同步元件的实现机制会有不同,我以上所描述的邮箱是基于T-Kernel规范的。

如果A要发M1给B,那么其实他们就使用同一个邮箱。也就是说,A是发送者,B是接收者。那么A端调用send_mail(&mail_box, &M1)发送消息。此时,消息被系统存放在该指定邮箱的发送队列中;然后在B端调用receive_mail(&mail_box, &message)来接收消息。当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列时,B就能得到消息了。在全局共享存储区中可以有多个邮箱,而系统知道每个邮箱,并在特定时候对每个邮箱做消息搬送。

如果用示意图的话,可以是:

           接收消息队列:口口口口口
邮箱MB:
           发送消息队列:口口口口口

当A发送消息M1时:

           接收消息队列:M1口口口口
邮箱MB:
           发送消息队列:口口口口口

当操作系统达到某一合适时期,进行清理每个邮箱后:

           接收消息队列:口口口口口
邮箱MB:
           发送消息队列:M1口口口口

然后,系统通知B可以获得资源,那么M1就会放入message所在的地址中。

#22


to   zenny_chen:
你的陈述和你画的图好象不太相符,比如,你在文中说:“当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列时,B就能得到消息了。在全局共享存储区中可以有多个邮箱,而系统知道每个邮箱,并在特定时候对每个邮箱做消息搬送。”
但是你的示意图是消息先存在于邮箱B的接收消息队列,后放于B的发送消息队列。
我不知道你的陈述是正确的,还是你的示意图是正确的?


#23


不好意思,最后一个图拷贝粘贴错了,呵呵。发送和接受上下反一下。

#24


非常不错,感谢,呵呵。
现在我基本上理解了,还有最后几个相关问题:
你说”当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列“,这个所谓的”某个合适的时候“,是指什么时候,操作系统是用什么方式实现的?
还有,如果在操作系统将消息从发送队列移入接收队列以前,进程就执行receive_mail,那么,此接收操作是否会被阻塞?
最后,执行receive_mail时,是一次全部接收邮箱的接收队列的全部的消息,还是和消息队列一样,一条一条的从队首接收 ?

#25


引用 2 楼 yellowhwb 的回复:
邮箱是个比喻,就是说有人往里放东西,有人把东西拿出来用。 
这个跟消息队列很相似,消息队列就是一个task向队列里放消息,一个task从队列里拿消息。就是一个类比而已!

up

#26


引用 9 楼 zenny_chen 的回复:
邮箱是一个通过在系统共享存储区内传递消息来实现同步和通信的对象。 
每个邮箱包含一个用于发送消息的消息队列和一个用来接受消息的消息队列。由于是在共享存储区域,因此它对每个任务都是可见的。 

而一般的消息队列,还可用来处理任务与外部事件之间的通信。比如一个按键消息。然后其中一个任务可以在消息队列中尝试去获取消息。消息的分发可以由一个线程对立进行,或是通过事件处理例程进行发派。 

总的来说,邮箱的空…

学习~~~

#27


谢谢独钓雪的提问和zenny_chen的回答
学习了~
谢谢

#28


引用 24 楼 sdcer 的回复:
非常不错,感谢,呵呵。 
现在我基本上理解了,还有最后几个相关问题: 
你说”当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列“,这个所谓的”某个合适的时候“,是指什么时候,操作系统是用什么方式实现的? 
还有,如果在操作系统将消息从发送队列移入接收队列以前,进程就执行receive_mail,那么,此接收操作是否会被阻塞? 
最后,执行receive_mail时,是一次全部接收邮箱的接收队列的全部的…


呵呵,这次又问了那么多。
(1)这个“某个时候”,对于邮箱机制而言而是是 邮箱特定的。也就是说,对于不同的邮箱的应用可以定制这个传递时间。如果某个邮箱被定制为一向它发送消息,就立即将消息转到接收队列,那么它的工作就好像一般的消息队列那样。像上面所举的按键的例子,那么这个时间可以是系统指定的一个键值扫描的时间片的时间,如100ms,当到了100ms后发生超时中断时,消息搬送将在中断服务例程中进行。

(2)receive_mail会有阻塞,这个跟消息队列一样。

(3)receive_mail一般是获得全部消息,也就是通过指向消息队列的指针进行访问。当然,邮箱可以提供访问特定ID的消息,不过一般这种情况下就又等同于消息队列了。

#29


呵呵,我现在感觉邮箱本质上就是消息队列,越来越觉得邮箱只是消息队列的封装。
有没有邮箱实现的代码可供参考?

#30


对,你这样理解也没问题。邮箱在数据结构上是一个双队列。一端由发送方发送消息,然后由系统在某一时刻将发送队列中的消息移入接收消息队列。 
这就好比你写封信给你的一个朋友,你先是把信塞进邮筒,然后由邮局将邮筒的信件做统一批处理,最后分发给每户人家。这里其实也差不多,只不过这里没有邮递员和邮局的处理,而是发送者直接将信件发送到接收者家的邮箱中。 

对于一份邮件,它包含了消息ID,发送者以及接收者(就像你写信,要写发信人和收信人地址一样)以及消息内容(通常是一个void*指针)。在你投信出去时,系统可能并不会马上将发送的的信转到接收队列,而且发送方一次可以发多个信件,因此这个动作可能在特定事件下,如:调度、定时器超时等,或者是在DSR(延迟的中断服务例程)中进行处理。 
然后接收者就可以在指定的邮箱中等待接收信件了。 

像楼上的xiaopoy(10楼)和xxgamexx(8楼)都说的不错。邮箱的特点是可以批传输消息,也就是说一次可以发多份消息,或者是在很短的时间间隔内连续发送消息。对于某些需要批消息处理的可以使用邮箱机制。 

这里举个例子,比如说我们在玩PC时会有几个按键同时按下的情况(如:Alt+Delete+Ctrl)。这时可以利用邮箱来判断在某段时间内,有哪几个按键被同时按下。当按键扫描线程在扫到一个按键被按下时,立即将它放入邮箱,然后再扫,直到这段时间片被用完,系统将这些键值全都放入到邮箱的接收消息队列。然后在应用程序端可以通过邮箱接收到0个或多个键值的组合来作出不同的事件处理。

#1


阅读下 linux源码即可

#2


邮箱是个比喻,就是说有人往里放东西,有人把东西拿出来用。
这个跟消息队列很相似,消息队列就是一个task向队列里放消息,一个task从队列里拿消息。就是一个类比而已!

#3


什么书上的比喻,其实你只要知道消息是用队列存储的就可以了,其他的不必知道

#4


UP

#5


up

#6


形式上的相似吧,其它嘛……暂时不清楚,毕竟邮箱是一个完整的系统。

#7


up

#8


邮箱用于大数据的传送.
队列多用于处理有序的事件.


消息队列又是未必先进先出

#9


邮箱是一个通过在系统共享存储区内传递消息来实现同步和通信的对象。
每个邮箱包含一个用于发送消息的消息队列和一个用来接受消息的消息队列。由于是在共享存储区域,因此它对每个任务都是可见的。

而一般的消息队列,还可用来处理任务与外部事件之间的通信。比如一个按键消息。然后其中一个任务可以在消息队列中尝试去获取消息。消息的分发可以由一个线程对立进行,或是通过事件处理例程进行发派。

总的来说,邮箱的空间开销比一般的消息队列要大(每个邮箱包含两个消息队列),不过由于是共享的,因此任务之间的消息同步可以通过邮箱进行。而传统的消息队列除了在任务之间进行消息传递之外,还可以让事件处理例程进行消息发派。每个任务可以有一个私有的消息队列,然后该任务可以通过将自己队列的地址进行注册,告诉给系统;或者传递给其它任务。另外,传统的消息队列中的消息的长度可以是不定长的。而由于邮箱定义在全局共享区,一般每个邮箱的大小及规格是固定的。

它们的共同点是,如果某个任务去接受消息,但失败,那么它就会处于等待状态。这时也可以结合事件进行唤醒触发,不过系统或另一个任务向它发送消息后会自动将其唤醒。

#10


消息队列,习惯用管道来比喻
邮箱就管道中几个数据同时移动。

#11


#12


up星羽GG

#13


邮箱 
服务器上是 一些文件,比如收件箱 ,发件箱 
用户的 目录 可能用hash算法 来得到,
当然每个用户只对自己的 目录有读写权限.......

#14


两者有联系

#15


我认为zenny_chen的分析是比较符合我的要求。

1. 那我是不是可以理解为:邮箱是工作在共享内存区的一种特殊的消息队列?
我对消息队列是比较熟悉的,但不太了解邮箱的工作机制。
2. 邮箱在数据结构组织上,是不是也是一个队列?谢谢。

#16


对,你这样理解也没问题。邮箱在数据结构上是一个双队列。一端由发送方发送消息,然后由系统在某一时刻将发送队列中的消息移入接收消息队列。
这就好比你写封信给你的一个朋友,你先是把信塞进邮筒,然后由邮局将邮筒的信件做统一批处理,最后分发给每户人家。这里其实也差不多,只不过这里没有邮递员和邮局的处理,而是发送者直接将信件发送到接收者家的邮箱中。

对于一份邮件,它包含了消息ID,发送者以及接收者(就像你写信,要写发信人和收信人地址一样)以及消息内容(通常是一个void*指针)。在你投信出去时,系统可能并不会马上将发送的的信转到接收队列,而且发送方一次可以发多个信件,因此这个动作可能在特定事件下,如:调度、定时器超时等,或者是在DSR(延迟的中断服务例程)中进行处理。
然后接收者就可以在指定的邮箱中等待接收信件了。

像楼上的xiaopoy(10楼)和xxgamexx(8楼)都说的不错。邮箱的特点是可以批传输消息,也就是说一次可以发多份消息,或者是在很短的时间间隔内连续发送消息。对于某些需要批消息处理的可以使用邮箱机制。

这里举个例子,比如说我们在玩PC时会有几个按键同时按下的情况(如:Alt+Delete+Ctrl)。这时可以利用邮箱来判断在某段时间内,有哪几个按键被同时按下。当按键扫描线程在扫到一个按键被按下时,立即将它放入邮箱,然后再扫,直到这段时间片被用完,系统将这些键值全都放入到邮箱的接收消息队列。然后在应用程序端可以通过邮箱接收到0个或多个键值的组合来作出不同的事件处理。

#17


一般邮箱可能被做成单工的,也就是说对于一个邮箱,发送者不能逆转为接收者。然后,发送者和接收者都知道所创建邮箱的地址。

而对于消息队列,它的伸缩性比邮箱更强,可以做成各种形式的。对于一个消息一定有消息接收者的地址,系统将某个消息发送给接收者时,如果此时接收者处于阻塞状态,那么可以将其唤醒。而邮箱一般不是通过单个消息将接收者唤醒的,而是邮箱本身,即当系统将某个邮箱的发送队列中的消息送往接收队列之后,做唤醒操作。所以从实时性上看,消息队列应该比邮箱反应更快。不过,邮箱却可以捕获更多的实时内容。因为做一次唤醒,然后任务切换的消耗可能是比较大的。

#18


zenny_chen 回答好详细啊~~

#19


对于邮箱的发送消息队列和接收消息队列,应该怎么理解?
比如:进程A有一个邮箱a,a的发送消息队列是1,接收消息队列是2;
同理,进程B有一个邮箱b,b的发送消息队列是11,接收消息队列是22;

比如:进程A要发送一个消息M给进程B,那么这两个邮箱的消息队列是怎么样的处理过程?也就是说,消息M如何在这些队列中传递?谢谢!

#20


从嵌入式系统uc/os来说,邮箱跟消息队列在实现上是没有区别的,邮箱相当于只可以存放一条消息的消息队列,一般来说邮箱用于紧急任务,而消息队列用于平常的任务,所以邮箱里只放一条消息,因为一有消息立马就能得到处理,系统根本就没有机会往同一个邮箱里再存一条消息,所以从邮箱里取消息的任务都是非常高优先级的。

#21


嗯。对于不同的操作系统可能一些同步元件的实现机制会有不同,我以上所描述的邮箱是基于T-Kernel规范的。

如果A要发M1给B,那么其实他们就使用同一个邮箱。也就是说,A是发送者,B是接收者。那么A端调用send_mail(&mail_box, &M1)发送消息。此时,消息被系统存放在该指定邮箱的发送队列中;然后在B端调用receive_mail(&mail_box, &message)来接收消息。当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列时,B就能得到消息了。在全局共享存储区中可以有多个邮箱,而系统知道每个邮箱,并在特定时候对每个邮箱做消息搬送。

如果用示意图的话,可以是:

           接收消息队列:口口口口口
邮箱MB:
           发送消息队列:口口口口口

当A发送消息M1时:

           接收消息队列:M1口口口口
邮箱MB:
           发送消息队列:口口口口口

当操作系统达到某一合适时期,进行清理每个邮箱后:

           接收消息队列:口口口口口
邮箱MB:
           发送消息队列:M1口口口口

然后,系统通知B可以获得资源,那么M1就会放入message所在的地址中。

#22


to   zenny_chen:
你的陈述和你画的图好象不太相符,比如,你在文中说:“当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列时,B就能得到消息了。在全局共享存储区中可以有多个邮箱,而系统知道每个邮箱,并在特定时候对每个邮箱做消息搬送。”
但是你的示意图是消息先存在于邮箱B的接收消息队列,后放于B的发送消息队列。
我不知道你的陈述是正确的,还是你的示意图是正确的?


#23


不好意思,最后一个图拷贝粘贴错了,呵呵。发送和接受上下反一下。

#24


非常不错,感谢,呵呵。
现在我基本上理解了,还有最后几个相关问题:
你说”当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列“,这个所谓的”某个合适的时候“,是指什么时候,操作系统是用什么方式实现的?
还有,如果在操作系统将消息从发送队列移入接收队列以前,进程就执行receive_mail,那么,此接收操作是否会被阻塞?
最后,执行receive_mail时,是一次全部接收邮箱的接收队列的全部的消息,还是和消息队列一样,一条一条的从队首接收 ?

#25


引用 2 楼 yellowhwb 的回复:
邮箱是个比喻,就是说有人往里放东西,有人把东西拿出来用。 
这个跟消息队列很相似,消息队列就是一个task向队列里放消息,一个task从队列里拿消息。就是一个类比而已!

up

#26


引用 9 楼 zenny_chen 的回复:
邮箱是一个通过在系统共享存储区内传递消息来实现同步和通信的对象。 
每个邮箱包含一个用于发送消息的消息队列和一个用来接受消息的消息队列。由于是在共享存储区域,因此它对每个任务都是可见的。 

而一般的消息队列,还可用来处理任务与外部事件之间的通信。比如一个按键消息。然后其中一个任务可以在消息队列中尝试去获取消息。消息的分发可以由一个线程对立进行,或是通过事件处理例程进行发派。 

总的来说,邮箱的空…

学习~~~

#27


谢谢独钓雪的提问和zenny_chen的回答
学习了~
谢谢

#28


引用 24 楼 sdcer 的回复:
非常不错,感谢,呵呵。 
现在我基本上理解了,还有最后几个相关问题: 
你说”当在某个合适的时刻,系统将该邮箱的发送队列中的消息全都搬送到接收消息队列“,这个所谓的”某个合适的时候“,是指什么时候,操作系统是用什么方式实现的? 
还有,如果在操作系统将消息从发送队列移入接收队列以前,进程就执行receive_mail,那么,此接收操作是否会被阻塞? 
最后,执行receive_mail时,是一次全部接收邮箱的接收队列的全部的…


呵呵,这次又问了那么多。
(1)这个“某个时候”,对于邮箱机制而言而是是 邮箱特定的。也就是说,对于不同的邮箱的应用可以定制这个传递时间。如果某个邮箱被定制为一向它发送消息,就立即将消息转到接收队列,那么它的工作就好像一般的消息队列那样。像上面所举的按键的例子,那么这个时间可以是系统指定的一个键值扫描的时间片的时间,如100ms,当到了100ms后发生超时中断时,消息搬送将在中断服务例程中进行。

(2)receive_mail会有阻塞,这个跟消息队列一样。

(3)receive_mail一般是获得全部消息,也就是通过指向消息队列的指针进行访问。当然,邮箱可以提供访问特定ID的消息,不过一般这种情况下就又等同于消息队列了。

#29


呵呵,我现在感觉邮箱本质上就是消息队列,越来越觉得邮箱只是消息队列的封装。
有没有邮箱实现的代码可供参考?

#30


对,你这样理解也没问题。邮箱在数据结构上是一个双队列。一端由发送方发送消息,然后由系统在某一时刻将发送队列中的消息移入接收消息队列。 
这就好比你写封信给你的一个朋友,你先是把信塞进邮筒,然后由邮局将邮筒的信件做统一批处理,最后分发给每户人家。这里其实也差不多,只不过这里没有邮递员和邮局的处理,而是发送者直接将信件发送到接收者家的邮箱中。 

对于一份邮件,它包含了消息ID,发送者以及接收者(就像你写信,要写发信人和收信人地址一样)以及消息内容(通常是一个void*指针)。在你投信出去时,系统可能并不会马上将发送的的信转到接收队列,而且发送方一次可以发多个信件,因此这个动作可能在特定事件下,如:调度、定时器超时等,或者是在DSR(延迟的中断服务例程)中进行处理。 
然后接收者就可以在指定的邮箱中等待接收信件了。 

像楼上的xiaopoy(10楼)和xxgamexx(8楼)都说的不错。邮箱的特点是可以批传输消息,也就是说一次可以发多份消息,或者是在很短的时间间隔内连续发送消息。对于某些需要批消息处理的可以使用邮箱机制。 

这里举个例子,比如说我们在玩PC时会有几个按键同时按下的情况(如:Alt+Delete+Ctrl)。这时可以利用邮箱来判断在某段时间内,有哪几个按键被同时按下。当按键扫描线程在扫到一个按键被按下时,立即将它放入邮箱,然后再扫,直到这段时间片被用完,系统将这些键值全都放入到邮箱的接收消息队列。然后在应用程序端可以通过邮箱接收到0个或多个键值的组合来作出不同的事件处理。