Reputation: 139
I want to spawn a number of processes that will respond to messages they receive. This is simple. However, I also want to have a process that is able to block the output of another process.
In another language I might set a flag and check the status of that flag before sending a message. But since Erlang doesn't have mutable variables, how might I achieve that?
I can certainly add a pattern in a receive
to watch for a suppression message. I just don't know what to do with it next.
I don't really like the idea of using an ETS table just for this, as that breaks a nice distributed model. Equally I'm not too concerned about concurrency problems, but I'd like to design this in the most appropriate fashion.
Upvotes: 0
Views: 146
Reputation: 2723
Each echo server can have its own state which indicates whether it is currently muted. Other processes can toggle that state with mute/unmute messages. Before responding to a message, the echo server will check the state and act appropriately.
For example:
1> {ok, Pid} = echo:start_link().
{ok,<0.99.0>}
2> echo:echo(Pid, "this message will be echoed.").
#Ref<0.0.0.443>
3> echo:echo(Pid, "as will this message..").
#Ref<0.0.0.447>
4> echo:mute(Pid).
ok
5> echo:echo(Pid, "this message will not.").
#Ref<0.0.0.457>
6> echo:unmute(Pid).
ok
7> echo:echo(Pid, "but this one will..").
#Ref<0.0.0.461>
8> flush().
Shell got {#Ref<0.0.0.443>,"this message will be echoed."}
Shell got {#Ref<0.0.0.447>,"as will this message.."}
Shell got {#Ref<0.0.0.461>,"but this one will.."}
ok
9> echo:stop(Pid).
ok
code:
-module(echo).
-behaviour(gen_server).
%% API
-export([start_link/0,
echo/2,
mute/1,
unmute/1,
stop/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {mute=false}).
%%%===================================================================
%%% API
%%%===================================================================
start_link() ->
gen_server:start_link(?MODULE, [], []).
echo(Pid, Msg) ->
Ref = make_ref(),
gen_server:cast(Pid, {echo, self(), Ref, Msg}),
Ref.
mute(Pid) ->
gen_server:cast(Pid, mute).
unmute(Pid) ->
gen_server:cast(Pid, unmute).
stop(Pid) ->
gen_server:cast(Pid, stop).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
init([]) ->
{ok, #state{}}.
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast({echo, From, Tag, Msg}, #state{mute=false} = State) ->
From ! {Tag, Msg},
{noreply, State};
handle_cast({echo, _From, _Tag, _Msg}, #state{mute=true} = State) ->
{noreply, State};
handle_cast(mute, State) ->
{noreply, State#state{mute=true}};
handle_cast(unmute, State) ->
{noreply, State#state{mute=false}};
handle_cast(stop, State) ->
{stop, normal, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
Upvotes: 2