erlangerlang-shell

Erlang receive the message and print that message


-module(cooperate).
-compile(export_all).

producer(_Pid, 0) ->
    done;
producer(Pid, N) -> 
    Pid ! {producer, N},
    io:format("process ~p producing ~p~n", [self(), rand:uniform(N)]),
    producer(Pid, N-1).

consumer() ->
    receive
        {producer,Pid} ->
            timer:sleep(10),io:format("process ~p consuming ~p~n", [self(), Pid]),
            consumer()
        after 40 ->
            stopping_terminus
        end.

go() ->
    Pid = spawn(cooperate, consumer, []),
    spawn(cooperate, producer, [Pid, 3]).

Expecting:

process <x.xx.x> producing 2
process <x.xx.x> producing 100
process <x.xx.x> producing 555
process <x.xx.x> consuming 2
process <x.xx.x> consuming 100
process <x.xx.x> consuming 555

I successfully producing random number like 2, 100, 555. Now, I want to sent the message to consumer and print them out. By the code above, I can only print consuming 3,2,1 due to the producer(Pid, N-1).


Solution

  • This line:

    Pid ! {producer, N},
    

    sends the message {producer, N} to the consumer. For example, the consumer will receive a message like {producer, 3}. You should be aware that in the consumer's receive statement:

    receive
        {producer,Pid} ->
    

    Pid will not match a pid. Just because you name a variable Pid, does not mean that it will actually match a pid. A pid is its own type in erlang--it is not an integer. A pid looks like the following when printed in the shell:

     <0.83.0>
    

    In your receive, Pid will actually match N, and N is not a pid, rather N is just an integer you pass as an argument. Do not name variables Pid that do not actually match a pid.

    If you want the producer to send a random number to the consumer, how would you do that? Well, you need the producer to send a message like {producer, SomeRandomNumber}. How do you do that?

    Pid ! {producer, SomeRandomNumber}
    

    If the consumer needs to distinguish between the messages that contain N and the messages that contain SomeRandomNumber, then you can send the messages like this:

    Pid ! {producer, producer_id, N}
    Pid ! {producer, rand_num, SomeRandomNumber}
    

    ( or even Pid ! {producer, N, SomeRandomNumber} )

    Then in the consumer's receive statement, you can use matching to do different things for the different types of messages that the consumer receives:

    receive
        {producer, producer_id, N} ->
            io:format("consumer ~p received message from producer ~p~n", [self(), N]),
            consumer();
        {producer, rand_num, SomeRandomNumber} ->
            io:format("consumer ~p got random number ~p~n", [self(), SomeRandomNumber]),
            consumer()
    after 40 ->
        stopping_terminus
    end.