[erlang-questions] gen_server and init

Loïc Hoguin essen@REDACTED
Tue Jul 28 11:23:35 CEST 2015

On 07/28/2015 10:05 AM, Jesper Louis Andersen wrote:
> On Mon, Jul 27, 2015 at 9:14 PM, Loïc Hoguin <essen@REDACTED
> <mailto:essen@REDACTED>> wrote:
>     I'm not sure what you wrote there but I can give you two scenarios
>     where it can fail off the top of my head. The first is very unlikely
>     and can only fail if you use the 0 timeout, while the second is
>     actually much easier to observe and can fail with both methods:
>     P1 calls start_link
>     P2 init (returns 0 timeout)
>     P2 yields before calling receive
>     P1 returns from start_link and sends P2 a message
>     P2 receives message
> Yes, this one is an obvious linearization problem. And indeed, using
> concuerror for this is the right tool for the job. But if you send
> yourself a message, concuerror reports, as expected that this is safe
> behaviour:
> Done! (Exit status: completed)
>    Summary: 0 errors, 3/3 interleavings explored
> and if that was not the case, there is something about the semantics of
> Erlang I need to learn :)

That is however assuming there are only two processes in your system, 
and everything is well written and pids don't wrap up (which they 
apparently do?)

Not to forget human error when an operator uses the shell and the pid/3 
function to test things out.

If you send yourself a message, or use the 0 timeout, you will also 
introduce another issue in your gen_server: you can trigger the clause 
again by simply sending the wrong message to the process. You could use 
the state to make sure you are indeed initializing, but that makes 
things a lot more complex.

The chances of a problem occuring are very low, but the chance of 
figuring out what happened when something does go wrong are much lower.

>     And:
>     P1 calls start_link
>     P2 in init subscribes to some kind of pubsub PS
>     PS sends P2 message(s)
>     P2 returns from init and receive those messages
> The fact that you give other processes access to the Pid the guarantee
> is lost. In that case, you can capture messages arriving before
> initialization and do something sensible with them, or you can do the
> enter_loop dance you suggested. I don't think it is a bad solution, but
> I would prefer to be able to do something simpler in common cases, and
> indeed, sending yourself a message is one of those, if we are to believe
> concuerror.

I'm not sure where the complexity lies with enter_loop. Instead of 
gen_server:start_link use proc_lib:spawn_link. Instead of returning from 
init, call gen_server:enter_loop. Done.

Then it depends if you need to have a synchronous start, in which case 
you will want to use proc_lib:start_link and proc_lib:init_ack. But in 
most cases this is not needed, especially since you now won't rely on 
hacks that require the start to be synchronous. :-)

Perhaps it is more obscure because people have relied on hacks and 
documented those hacks a lot more than enter_loop.

Loïc Hoguin
Author of The Erlanger Playbook,
A book about software development using Erlang

More information about the erlang-questions mailing list