<p>It is a consequence of the fact that the shell is interpreted; the way the pattern-and-guard condition is evaluated is that it is interpreted (from symbolic form) by the shell, which is a normal Erlang program. Thus the shell can't use normal receive for two reasons: the condition is too complex to be expressible as a fixed pattern+guard, and messages can't be put back into the queue once accepted.<br>

This is why the shell has to emulate 'receive' in this way.</p>
<div class="gmail_quote">Den 24/04/2012 21.24 skrev "Steve Vinoski" <<a href="mailto:vinoski@ieee.org">vinoski@ieee.org</a>>:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On Mon, Apr 23, 2012 at 3:56 AM, Attila Rajmund Nohl<br>
<<a href="mailto:attila.r.nohl@gmail.com">attila.r.nohl@gmail.com</a>> wrote:<br>
> 2012/4/23 吴磊 <<a href="mailto:mjollnir.ray@gmail.com">mjollnir.ray@gmail.com</a>>:<br>
>> Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:4:4]<br>
>> [async-threads:0] [hipe] [kernel-poll:false]<br>
>><br>
>> Eshell V5.9.1  (abort with ^G)<br>
>> 1> self().<br>
>> <0.32.0><br>
>> 2> process_flag(trap_exit, true).<br>
>> false<br>
>> 3>  spawn_link(fun() -> ok end).<br>
>> <0.36.0><br>
>> 4> process_info(self(), messages).<br>
>> {messages,[{'EXIT',<0.36.0>,normal}]}<br>
>> 5> receive X -> X end.<br>
>> {'EXIT',<0.36.0>,normal}<br>
>> 6>  spawn_link(fun() -> ok end).<br>
>> <0.40.0><br>
>> 7> process_info(self(), messages).<br>
>> {messages,[{'EXIT',<0.40.0>,normal}]}<br>
>> 8> receive X -> X end.<br>
>><br>
>> shell SUSPENDING .... WHAT's happed here?<br>
><br>
> X was already bound, so you were waiting for {'EXIT',<0.36.0>,normal},<br>
> but got {'EXIT',<0.40.0>,normal}<br>
<br>
That much is true, but there's something else interesting here. Look<br>
more carefully at the output from the second shell in the original<br>
message, repeated below:<br>
<br>
^G<br>
User switch command<br>
 --> s<br>
 --> c<br>
Eshell V5.9.1  (abort with ^G)<br>
1> process_info(pid(0,32,0), current_function).<br>
{current_function,{erl_eval,receive_clauses,6}}<br>
2> process_info(pid(0,32,0), messages).<br>
{messages,[]}<br>
<br>
The second call to process_info shows the first shell's message queue<br>
to be empty, when in fact it isn't. Could this be the problem to which<br>
the original author was actually referring?<br>
<br>
Here's a variant of the same. First, set X and then spawn a new<br>
process, same as in the original posting:<br>
<br>
Eshell V5.9.1  (abort with ^G)<br>
1> self().<br>
<0.31.0><br>
2> process_flag(trap_exit, true).<br>
false<br>
3> spawn_link(fun() -> ok end).<br>
<0.35.0><br>
4> process_info(self(), messages).<br>
{messages,[{'EXIT',<0.35.0>,normal}]}<br>
5> receive X -> X end.<br>
{'EXIT',<0.35.0>,normal}<br>
6> spawn_link(fun() -> ok end).<br>
<0.39.0><br>
<br>
At this point we should have an EXIT tuple in this shell's message<br>
queue. Next, start a new shell, and use it to verify that the first<br>
shell's message queue is not empty:<br>
<br>
^G<br>
User switch command<br>
 --> s<br>
 --> c<br>
Eshell V5.9.1  (abort with ^G)<br>
1> process_info(pid(0,31,0), messages).<br>
{messages,[{'EXIT',<0.39.0>,normal}]}<br>
<br>
Just what we expect to see. Now, get the pid of the second shell, and<br>
then switch back to the first shell. In the first shell, start a<br>
receive like in the original message, but add a 30 second timeout, and<br>
send a 'done' message to the second shell after the timeout:<br>
<br>
2> self().<br>
<0.43.0><br>
<br>
^G<br>
User switch command<br>
 --> c 1<br>
7> receive X -> X after 30000 -> pid(0,43,0) ! done end.<br>
<br>
Now quickly switch back to the second shell, check the first shell's<br>
message queue, and then wait for the 'done' message:<br>
<br>
User switch command<br>
 --> c 2<br>
3> process_info(pid(0,31,0), messages).<br>
{messages,[]}<br>
4> receive done -> process_info(pid(0,31,0), messages) end.<br>
{messages,[{'EXIT',<0.39.0>,normal}]}<br>
<br>
Check that out -- while the first shell is trying to receive X,<br>
examining its message queue from the second shell shows that queue to<br>
be empty, contrary to what we saw the first time we checked it from<br>
the second shell, where it held the EXIT tuple for the second spawned<br>
process. But after the first shell's receive times out and the second<br>
shell gets the 'done' message, checking the first shell's message<br>
queue again shows it to contain the same EXIT tuple as before.<br>
<br>
In section 8.6 of his book, Joe describes a "save queue" used during<br>
selective receive, and this behavior matches his description. But if<br>
you write a program that does the same thing, it acts differently;<br>
unlike the shell, you won't observe an empty message queue during a<br>
receive. So this behavior must be a shell thing. I don't know the<br>
details of why it acts this way -- chatting about it with Scott<br>
Fritchie, he guessed it might have something to do with the other<br>
messaging the shell has to do, but neither of us knows for sure. Can<br>
someone explain why the shell seems to use an actual "save queue"<br>
during a receive?<br>
<br>
--steve<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div>