Closing Channels in Erlang
In this example, we’ll use a jobs process to communicate work to be done from the main process to a worker process. When we have no more jobs for the worker, we’ll send a special message to indicate completion.
-module(closing_channels).
-export([main/0]).
main() ->
Jobs = spawn(fun() -> jobs_process([]) end),
Done = spawn(fun() -> done_process() end),
% This is the worker process. It repeatedly receives
% messages from Jobs. When it receives the 'close' atom,
% it knows that all jobs have been processed.
Worker = spawn(fun() -> worker_process(Jobs, Done) end),
% This sends 3 jobs to the worker via the Jobs process
[Jobs ! {job, J} || J <- lists:seq(1, 3)],
io:format("sent all jobs~n"),
Jobs ! close,
% We await the worker using a synchronization approach
receive
done -> ok
end,
% Checking if the Jobs process is still alive
case is_process_alive(Jobs) of
true -> io:format("Jobs process is still alive~n");
false -> io:format("Jobs process has terminated~n")
end.
jobs_process(Queue) ->
receive
{job, J} ->
jobs_process([J | Queue]);
{get_job, Pid} when Queue /= [] ->
[Job | Rest] = lists:reverse(Queue),
Pid ! {job, Job},
jobs_process(Rest);
{get_job, Pid} when Queue == [] ->
Pid ! no_more_jobs,
jobs_process([]);
close when Queue == [] ->
exit(normal);
close ->
jobs_process(Queue)
end.
worker_process(Jobs, Done) ->
Jobs ! {get_job, self()},
receive
{job, J} ->
io:format("received job ~p~n", [J]),
worker_process(Jobs, Done);
no_more_jobs ->
io:format("received all jobs~n"),
Done ! done
end.
done_process() ->
receive
done -> ok
end.To run the program, save it as closing_channels.erl and use the Erlang shell:
$ erl
1> c(closing_channels).
{ok,closing_channels}
2> closing_channels:main().
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
Jobs process has terminated
okIn this Erlang version, we use processes and message passing to mimic the behavior of channels in Go. The jobs_process acts as a queue for jobs, the worker_process receives and processes jobs, and the done_process is used for synchronization.
The concept of closing a channel is simulated by sending a close message to the jobs_process. When the jobs_process receives this message and its queue is empty, it terminates.
The worker process keeps requesting jobs until it receives a no_more_jobs message, at which point it signals completion to the done_process.
Finally, we check if the Jobs process is still alive, which is analogous to checking if a channel is closed in Go.
This example demonstrates how Erlang’s processes and message passing can be used to implement patterns similar to Go’s goroutines and channels.