Unidirectional linking?

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Unidirectional linking?

Igor Ribeiro Sucupira
Suppose there is a heavy operation Op that in some cases takes so long
to finish that the caller loses interest in the result and gives up.

I want to perform that operation in a way that allows me to:
1) Interrupt its execution if it does not finish in N milliseconds.
2) Interrupt its execution if the calling process exits (here I'm
already supposing Op has to be run in another Erlang process, due to
goal 1).

To implement that, it seems unidirectional linking would be needed. Is
there another safe and convenient way to do it?

The first idea I had was something like this:

Parent = self(),
Child = spawn_link(fun() -> Parent ! (catch Op) end),
receive Result -> Result
after N -> unlink(Child), exit(Child, timeout), timeout
end.

But, if Parent is killed by another process right after calling
unlink, Child would be left executing.
Another problem is that I don't want Parent to die if Child exits for
non-timeout reasons (although it seems very unlikely in the code
above, with the catch).

I was now thinking of substituting unlink(Child) with
process_flag(trap_exit, true) and then kill Child, receive its exit
message, set trap_exit to false again (I'm assuming it was false), and
finally check if there were other exit messages (suiciding if it was
the case).

But then the code would become too ugly, so I got lazy and decided to
post to this list.  :-)

What do you think?

Thanks.
Igor.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Bengt Kleberg
Greetings,

Uni-directional links are created with erlang:monitor/2.

Does this help?


bengt

On Wed, 2011-05-25 at 08:00 +0200, Igor Ribeiro Sucupira wrote:

> Suppose there is a heavy operation Op that in some cases takes so long
> to finish that the caller loses interest in the result and gives up.
>
> I want to perform that operation in a way that allows me to:
> 1) Interrupt its execution if it does not finish in N milliseconds.
> 2) Interrupt its execution if the calling process exits (here I'm
> already supposing Op has to be run in another Erlang process, due to
> goal 1).
>
> To implement that, it seems unidirectional linking would be needed. Is
> there another safe and convenient way to do it?
>
> The first idea I had was something like this:
>
> Parent = self(),
> Child = spawn_link(fun() -> Parent ! (catch Op) end),
> receive Result -> Result
> after N -> unlink(Child), exit(Child, timeout), timeout
> end.
>
> But, if Parent is killed by another process right after calling
> unlink, Child would be left executing.
> Another problem is that I don't want Parent to die if Child exits for
> non-timeout reasons (although it seems very unlikely in the code
> above, with the catch).
>
> I was now thinking of substituting unlink(Child) with
> process_flag(trap_exit, true) and then kill Child, receive its exit
> message, set trap_exit to false again (I'm assuming it was false), and
> finally check if there were other exit messages (suiciding if it was
> the case).
>
> But then the code would become too ugly, so I got lazy and decided to
> post to this list.  :-)
>
> What do you think?
>
> Thanks.
> Igor.
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

mazenharake
In reply to this post by Igor Ribeiro Sucupira
Why would someone "kill the parent"? Do you have processes which are randomly choosing other processes to terminate? ;)

If your answer is "No" then I would suggest that you just kill the worker processes that is taking to long, kill it in cold blood, imo.

There is no reason to think about too many "if"-scenarios when the scenarios are too far fetched. Try the simple version first :)

otherwise you can either trap_exits or use monitors instead.

/M

On 25 May 2011 08:00, Igor Ribeiro Sucupira <[hidden email]> wrote:
Suppose there is a heavy operation Op that in some cases takes so long
to finish that the caller loses interest in the result and gives up.

I want to perform that operation in a way that allows me to:
1) Interrupt its execution if it does not finish in N milliseconds.
2) Interrupt its execution if the calling process exits (here I'm
already supposing Op has to be run in another Erlang process, due to
goal 1).

To implement that, it seems unidirectional linking would be needed. Is
there another safe and convenient way to do it?

The first idea I had was something like this:

Parent = self(),
Child = spawn_link(fun() -> Parent ! (catch Op) end),
receive Result -> Result
after N -> unlink(Child), exit(Child, timeout), timeout
end.

But, if Parent is killed by another process right after calling
unlink, Child would be left executing.
Another problem is that I don't want Parent to die if Child exits for
non-timeout reasons (although it seems very unlikely in the code
above, with the catch).

I was now thinking of substituting unlink(Child) with
process_flag(trap_exit, true) and then kill Child, receive its exit
message, set trap_exit to false again (I'm assuming it was false), and
finally check if there were other exit messages (suiciding if it was
the case).

But then the code would become too ugly, so I got lazy and decided to
post to this list.  :-)

What do you think?

Thanks.
Igor.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Igor Ribeiro Sucupira
In reply to this post by Bengt Kleberg
I couldn't see a way of using monitors in this example. I would need
the child process to monitor its parent, but the child is busy
performing Op.

Thanks.
Igor.

On Wed, May 25, 2011 at 3:16 AM, Bengt Kleberg
<[hidden email]> wrote:

> Greetings,
>
> Uni-directional links are created with erlang:monitor/2.
>
> Does this help?
>
>
> bengt
>
> On Wed, 2011-05-25 at 08:00 +0200, Igor Ribeiro Sucupira wrote:
>> Suppose there is a heavy operation Op that in some cases takes so long
>> to finish that the caller loses interest in the result and gives up.
>>
>> I want to perform that operation in a way that allows me to:
>> 1) Interrupt its execution if it does not finish in N milliseconds.
>> 2) Interrupt its execution if the calling process exits (here I'm
>> already supposing Op has to be run in another Erlang process, due to
>> goal 1).
>>
>> To implement that, it seems unidirectional linking would be needed. Is
>> there another safe and convenient way to do it?
>>
>> The first idea I had was something like this:
>>
>> Parent = self(),
>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>> receive Result -> Result
>> after N -> unlink(Child), exit(Child, timeout), timeout
>> end.
>>
>> But, if Parent is killed by another process right after calling
>> unlink, Child would be left executing.
>> Another problem is that I don't want Parent to die if Child exits for
>> non-timeout reasons (although it seems very unlikely in the code
>> above, with the catch).
>>
>> I was now thinking of substituting unlink(Child) with
>> process_flag(trap_exit, true) and then kill Child, receive its exit
>> message, set trap_exit to false again (I'm assuming it was false), and
>> finally check if there were other exit messages (suiciding if it was
>> the case).
>>
>> But then the code would become too ugly, so I got lazy and decided to
>> post to this list.  :-)
>>
>> What do you think?
>>
>> Thanks.
>> Igor.
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Norton Joseph Wayne

Igor -

I suggest to add a simple proxy process (or add this functionality to the  
parent process if it is better suited) that has a receive clause for the  
operation's response, the operation's monitor exit, and an after clause  
with the operation's timeout.  If timeout occurs, you can demonitor and  
kill the operation's process.

- Joe N

On Wed, 25 May 2011 15:24:23 +0900, Igor Ribeiro Sucupira  
<[hidden email]> wrote:

> I couldn't see a way of using monitors in this example. I would need
> the child process to monitor its parent, but the child is busy
> performing Op.
>
> Thanks.
> Igor.
>
> On Wed, May 25, 2011 at 3:16 AM, Bengt Kleberg
> <[hidden email]> wrote:
>> Greetings,
>>
>> Uni-directional links are created with erlang:monitor/2.
>>
>> Does this help?
>>
>>
>> bengt
>>
>> On Wed, 2011-05-25 at 08:00 +0200, Igor Ribeiro Sucupira wrote:
>>> Suppose there is a heavy operation Op that in some cases takes so long
>>> to finish that the caller loses interest in the result and gives up.
>>>
>>> I want to perform that operation in a way that allows me to:
>>> 1) Interrupt its execution if it does not finish in N milliseconds.
>>> 2) Interrupt its execution if the calling process exits (here I'm
>>> already supposing Op has to be run in another Erlang process, due to
>>> goal 1).
>>>
>>> To implement that, it seems unidirectional linking would be needed. Is
>>> there another safe and convenient way to do it?
>>>
>>> The first idea I had was something like this:
>>>
>>> Parent = self(),
>>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>>> receive Result -> Result
>>> after N -> unlink(Child), exit(Child, timeout), timeout
>>> end.
>>>
>>> But, if Parent is killed by another process right after calling
>>> unlink, Child would be left executing.
>>> Another problem is that I don't want Parent to die if Child exits for
>>> non-timeout reasons (although it seems very unlikely in the code
>>> above, with the catch).
>>>
>>> I was now thinking of substituting unlink(Child) with
>>> process_flag(trap_exit, true) and then kill Child, receive its exit
>>> message, set trap_exit to false again (I'm assuming it was false), and
>>> finally check if there were other exit messages (suiciding if it was
>>> the case).
>>>
>>> But then the code would become too ugly, so I got lazy and decided to
>>> post to this list.  :-)
>>>
>>> What do you think?
>>>
>>> Thanks.
>>> Igor.
>>> _______________________________________________
>>> erlang-questions mailing list
>>> [hidden email]
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions


--
[hidden email]
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Igor Ribeiro Sucupira
I was thinking about something like that right now, trying to convince
myself that it could work with a third process. :)  Thanks! I will try
it.

Best regards.
Igor.

--
"The secret of joy in work is contained in one word - excellence. To
know how to do something well is to enjoy it." - Pearl S. Buck.


On Wed, May 25, 2011 at 3:34 AM, Joseph Wayne Norton
<[hidden email]> wrote:

>
> Igor -
>
> I suggest to add a simple proxy process (or add this functionality to the
> parent process if it is better suited) that has a receive clause for the
> operation's response, the operation's monitor exit, and an after clause with
> the operation's timeout.  If timeout occurs, you can demonitor and kill the
> operation's process.
>
> - Joe N
>
> On Wed, 25 May 2011 15:24:23 +0900, Igor Ribeiro Sucupira <[hidden email]>
> wrote:
>
>> I couldn't see a way of using monitors in this example. I would need
>> the child process to monitor its parent, but the child is busy
>> performing Op.
>>
>> Thanks.
>> Igor.
>>
>> On Wed, May 25, 2011 at 3:16 AM, Bengt Kleberg
>> <[hidden email]> wrote:
>>>
>>> Greetings,
>>>
>>> Uni-directional links are created with erlang:monitor/2.
>>>
>>> Does this help?
>>>
>>>
>>> bengt
>>>
>>> On Wed, 2011-05-25 at 08:00 +0200, Igor Ribeiro Sucupira wrote:
>>>>
>>>> Suppose there is a heavy operation Op that in some cases takes so long
>>>> to finish that the caller loses interest in the result and gives up.
>>>>
>>>> I want to perform that operation in a way that allows me to:
>>>> 1) Interrupt its execution if it does not finish in N milliseconds.
>>>> 2) Interrupt its execution if the calling process exits (here I'm
>>>> already supposing Op has to be run in another Erlang process, due to
>>>> goal 1).
>>>>
>>>> To implement that, it seems unidirectional linking would be needed. Is
>>>> there another safe and convenient way to do it?
>>>>
>>>> The first idea I had was something like this:
>>>>
>>>> Parent = self(),
>>>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>>>> receive Result -> Result
>>>> after N -> unlink(Child), exit(Child, timeout), timeout
>>>> end.
>>>>
>>>> But, if Parent is killed by another process right after calling
>>>> unlink, Child would be left executing.
>>>> Another problem is that I don't want Parent to die if Child exits for
>>>> non-timeout reasons (although it seems very unlikely in the code
>>>> above, with the catch).
>>>>
>>>> I was now thinking of substituting unlink(Child) with
>>>> process_flag(trap_exit, true) and then kill Child, receive its exit
>>>> message, set trap_exit to false again (I'm assuming it was false), and
>>>> finally check if there were other exit messages (suiciding if it was
>>>> the case).
>>>>
>>>> But then the code would become too ugly, so I got lazy and decided to
>>>> post to this list.  :-)
>>>>
>>>> What do you think?
>>>>
>>>> Thanks.
>>>> Igor.
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> [hidden email]
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> [hidden email]
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
>
> --
> [hidden email]
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Igor Ribeiro Sucupira
In reply to this post by mazenharake
Supposing someone used the same logic (with timeout/kill) to spawn the
parent process, the parent could be killed at any moment (but yeah: it
would be bad luck to have that happening right after it called
unlink).

Thanks.
Igor.

On Wed, May 25, 2011 at 3:20 AM, Mazen Harake <[hidden email]> wrote:

> Why would someone "kill the parent"? Do you have processes which are
> randomly choosing other processes to terminate? ;)
>
> If your answer is "No" then I would suggest that you just kill the worker
> processes that is taking to long, kill it in cold blood, imo.
>
> There is no reason to think about too many "if"-scenarios when the scenarios
> are too far fetched. Try the simple version first :)
>
> otherwise you can either trap_exits or use monitors instead.
>
> /M
>
> On 25 May 2011 08:00, Igor Ribeiro Sucupira <[hidden email]> wrote:
>>
>> Suppose there is a heavy operation Op that in some cases takes so long
>> to finish that the caller loses interest in the result and gives up.
>>
>> I want to perform that operation in a way that allows me to:
>> 1) Interrupt its execution if it does not finish in N milliseconds.
>> 2) Interrupt its execution if the calling process exits (here I'm
>> already supposing Op has to be run in another Erlang process, due to
>> goal 1).
>>
>> To implement that, it seems unidirectional linking would be needed. Is
>> there another safe and convenient way to do it?
>>
>> The first idea I had was something like this:
>>
>> Parent = self(),
>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>> receive Result -> Result
>> after N -> unlink(Child), exit(Child, timeout), timeout
>> end.
>>
>> But, if Parent is killed by another process right after calling
>> unlink, Child would be left executing.
>> Another problem is that I don't want Parent to die if Child exits for
>> non-timeout reasons (although it seems very unlikely in the code
>> above, with the catch).
>>
>> I was now thinking of substituting unlink(Child) with
>> process_flag(trap_exit, true) and then kill Child, receive its exit
>> message, set trap_exit to false again (I'm assuming it was false), and
>> finally check if there were other exit messages (suiciding if it was
>> the case).
>>
>> But then the code would become too ugly, so I got lazy and decided to
>> post to this list.  :-)
>>
>> What do you think?
>>
>> Thanks.
>> Igor.
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Igor Ribeiro Sucupira
In reply to this post by Igor Ribeiro Sucupira
The Parent might call this right before calling unlink:

spawn(fun() -> erlang:monitor(Parent), erlang:monitor(Child), receive
{'DOWN', _, _, _, _} -> erlang:exit(Child, timeout) end end),

This way, if Parent dies right after calling unlink, the monitor
process will kill Child and then exit.

If the Parent succeeds in unlinking and then killing Child, the
monitor will be notified of the death of Child and will also finish.

Not perfect, not beautiful, but maybe it is enough.

Thanks.
Igor.

On Wed, May 25, 2011 at 3:39 AM, Igor Ribeiro Sucupira <[hidden email]> wrote:

> I was thinking about something like that right now, trying to convince
> myself that it could work with a third process. :)  Thanks! I will try
> it.
>
> Best regards.
> Igor.
>
> --
> "The secret of joy in work is contained in one word - excellence. To
> know how to do something well is to enjoy it." - Pearl S. Buck.
>
>
> On Wed, May 25, 2011 at 3:34 AM, Joseph Wayne Norton
> <[hidden email]> wrote:
>>
>> Igor -
>>
>> I suggest to add a simple proxy process (or add this functionality to the
>> parent process if it is better suited) that has a receive clause for the
>> operation's response, the operation's monitor exit, and an after clause with
>> the operation's timeout.  If timeout occurs, you can demonitor and kill the
>> operation's process.
>>
>> - Joe N
>>
>> On Wed, 25 May 2011 15:24:23 +0900, Igor Ribeiro Sucupira <[hidden email]>
>> wrote:
>>
>>> I couldn't see a way of using monitors in this example. I would need
>>> the child process to monitor its parent, but the child is busy
>>> performing Op.
>>>
>>> Thanks.
>>> Igor.
>>>
>>> On Wed, May 25, 2011 at 3:16 AM, Bengt Kleberg
>>> <[hidden email]> wrote:
>>>>
>>>> Greetings,
>>>>
>>>> Uni-directional links are created with erlang:monitor/2.
>>>>
>>>> Does this help?
>>>>
>>>>
>>>> bengt
>>>>
>>>> On Wed, 2011-05-25 at 08:00 +0200, Igor Ribeiro Sucupira wrote:
>>>>>
>>>>> Suppose there is a heavy operation Op that in some cases takes so long
>>>>> to finish that the caller loses interest in the result and gives up.
>>>>>
>>>>> I want to perform that operation in a way that allows me to:
>>>>> 1) Interrupt its execution if it does not finish in N milliseconds.
>>>>> 2) Interrupt its execution if the calling process exits (here I'm
>>>>> already supposing Op has to be run in another Erlang process, due to
>>>>> goal 1).
>>>>>
>>>>> To implement that, it seems unidirectional linking would be needed. Is
>>>>> there another safe and convenient way to do it?
>>>>>
>>>>> The first idea I had was something like this:
>>>>>
>>>>> Parent = self(),
>>>>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>>>>> receive Result -> Result
>>>>> after N -> unlink(Child), exit(Child, timeout), timeout
>>>>> end.
>>>>>
>>>>> But, if Parent is killed by another process right after calling
>>>>> unlink, Child would be left executing.
>>>>> Another problem is that I don't want Parent to die if Child exits for
>>>>> non-timeout reasons (although it seems very unlikely in the code
>>>>> above, with the catch).
>>>>>
>>>>> I was now thinking of substituting unlink(Child) with
>>>>> process_flag(trap_exit, true) and then kill Child, receive its exit
>>>>> message, set trap_exit to false again (I'm assuming it was false), and
>>>>> finally check if there were other exit messages (suiciding if it was
>>>>> the case).
>>>>>
>>>>> But then the code would become too ugly, so I got lazy and decided to
>>>>> post to this list.  :-)
>>>>>
>>>>> What do you think?
>>>>>
>>>>> Thanks.
>>>>> Igor.
>>>>> _______________________________________________
>>>>> erlang-questions mailing list
>>>>> [hidden email]
>>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> [hidden email]
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> [hidden email]
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>>
>> --
>> [hidden email]
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

mazenharake
In reply to this post by Igor Ribeiro Sucupira
Perhaps something like this:

process_flag(trap_exit, true),
Parent = self(),
Child = spawn_link(fun() -> Parent ! (catch Op) end),
receive
  {'EXIT', ParentsParent, Reason} ->
    exit(Reason);
  Result ->
    Result
 after N ->
    unlink(Child),
    exit(Child, timeout),
    timeout
end.

if you get an exit signal from the parent's parent you will exit if you are in the receive clause and you will ignore it (unless it is a kill) if you are in between the unlink and exit child?

I do however still think that this is very defensive and that the probability of getting an exit between unlink and exit is very small unless the timeout in N is exactly the same (very very close to) the timeout that the parent's parent has for exiting the parent.



On 25 May 2011 08:51, Igor Ribeiro Sucupira <[hidden email]> wrote:
Supposing someone used the same logic (with timeout/kill) to spawn the
parent process, the parent could be killed at any moment (but yeah: it
would be bad luck to have that happening right after it called
unlink).

Thanks.
Igor.

On Wed, May 25, 2011 at 3:20 AM, Mazen Harake <[hidden email]> wrote:
> Why would someone "kill the parent"? Do you have processes which are
> randomly choosing other processes to terminate? ;)
>
> If your answer is "No" then I would suggest that you just kill the worker
> processes that is taking to long, kill it in cold blood, imo.
>
> There is no reason to think about too many "if"-scenarios when the scenarios
> are too far fetched. Try the simple version first :)
>
> otherwise you can either trap_exits or use monitors instead.
>
> /M
>
> On 25 May 2011 08:00, Igor Ribeiro Sucupira <[hidden email]> wrote:
>>
>> Suppose there is a heavy operation Op that in some cases takes so long
>> to finish that the caller loses interest in the result and gives up.
>>
>> I want to perform that operation in a way that allows me to:
>> 1) Interrupt its execution if it does not finish in N milliseconds.
>> 2) Interrupt its execution if the calling process exits (here I'm
>> already supposing Op has to be run in another Erlang process, due to
>> goal 1).
>>
>> To implement that, it seems unidirectional linking would be needed. Is
>> there another safe and convenient way to do it?
>>
>> The first idea I had was something like this:
>>
>> Parent = self(),
>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>> receive Result -> Result
>> after N -> unlink(Child), exit(Child, timeout), timeout
>> end.
>>
>> But, if Parent is killed by another process right after calling
>> unlink, Child would be left executing.
>> Another problem is that I don't want Parent to die if Child exits for
>> non-timeout reasons (although it seems very unlikely in the code
>> above, with the catch).
>>
>> I was now thinking of substituting unlink(Child) with
>> process_flag(trap_exit, true) and then kill Child, receive its exit
>> message, set trap_exit to false again (I'm assuming it was false), and
>> finally check if there were other exit messages (suiciding if it was
>> the case).
>>
>> But then the code would become too ugly, so I got lazy and decided to
>> post to this list.  :-)
>>
>> What do you think?
>>
>> Thanks.
>> Igor.
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
>


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Igor Ribeiro Sucupira
Parent will probably need to do more work after it gets the result
from Child, so, in the end, you would need to restore trap_exit to
false (unless it wasn't false before) and then call receive again, to
make sure there weren't other exit messages while trap_exit was true.

That's what worries me about the trap_exit solution: the more code you
need, the more conditions you may be forgetting to consider.

I am planning to put that logic inside of a "general" function
(something like catch_apply(Module, Function, Args, Timeout)) and use
it in my system (that handles hundreds of requests per second).
It may happen, for example, that Op1 calls OpA and OpB, while Op2
calls OpC and OpA, with Op1 and Op2 having different timeouts. So, it
may get very wild and, having some experience with that kind of load,
I have seen in practice that race conditions are very real.

In the first use case I'm planning, leaking Child or having Parent
dying (or not dying) by mistake sometimes might not be so bad. But one
day other people may begin to use the function for other operations
and I don't want anybody hurt.  :)

Thanks!
Igor.

--
"The secret of joy in work is contained in one word - excellence. To
know how to do something well is to enjoy it." - Pearl S. Buck.


On Wed, May 25, 2011 at 4:28 AM, Mazen Harake <[hidden email]> wrote:

> Perhaps something like this:
>
> process_flag(trap_exit, true),
> Parent = self(),
> Child = spawn_link(fun() -> Parent ! (catch Op) end),
> receive
>   {'EXIT', ParentsParent, Reason} ->
>     exit(Reason);
>   Result ->
>     Result
>  after N ->
>     unlink(Child),
>     exit(Child, timeout),
>     timeout
> end.
>
> if you get an exit signal from the parent's parent you will exit if you are
> in the receive clause and you will ignore it (unless it is a kill) if you
> are in between the unlink and exit child?
>
> I do however still think that this is very defensive and that the
> probability of getting an exit between unlink and exit is very small unless
> the timeout in N is exactly the same (very very close to) the timeout that
> the parent's parent has for exiting the parent.
>
>
>
> On 25 May 2011 08:51, Igor Ribeiro Sucupira <[hidden email]> wrote:
>>
>> Supposing someone used the same logic (with timeout/kill) to spawn the
>> parent process, the parent could be killed at any moment (but yeah: it
>> would be bad luck to have that happening right after it called
>> unlink).
>>
>> Thanks.
>> Igor.
>>
>> On Wed, May 25, 2011 at 3:20 AM, Mazen Harake <[hidden email]>
>> wrote:
>> > Why would someone "kill the parent"? Do you have processes which are
>> > randomly choosing other processes to terminate? ;)
>> >
>> > If your answer is "No" then I would suggest that you just kill the
>> > worker
>> > processes that is taking to long, kill it in cold blood, imo.
>> >
>> > There is no reason to think about too many "if"-scenarios when the
>> > scenarios
>> > are too far fetched. Try the simple version first :)
>> >
>> > otherwise you can either trap_exits or use monitors instead.
>> >
>> > /M
>> >
>> > On 25 May 2011 08:00, Igor Ribeiro Sucupira <[hidden email]> wrote:
>> >>
>> >> Suppose there is a heavy operation Op that in some cases takes so long
>> >> to finish that the caller loses interest in the result and gives up.
>> >>
>> >> I want to perform that operation in a way that allows me to:
>> >> 1) Interrupt its execution if it does not finish in N milliseconds.
>> >> 2) Interrupt its execution if the calling process exits (here I'm
>> >> already supposing Op has to be run in another Erlang process, due to
>> >> goal 1).
>> >>
>> >> To implement that, it seems unidirectional linking would be needed. Is
>> >> there another safe and convenient way to do it?
>> >>
>> >> The first idea I had was something like this:
>> >>
>> >> Parent = self(),
>> >> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>> >> receive Result -> Result
>> >> after N -> unlink(Child), exit(Child, timeout), timeout
>> >> end.
>> >>
>> >> But, if Parent is killed by another process right after calling
>> >> unlink, Child would be left executing.
>> >> Another problem is that I don't want Parent to die if Child exits for
>> >> non-timeout reasons (although it seems very unlikely in the code
>> >> above, with the catch).
>> >>
>> >> I was now thinking of substituting unlink(Child) with
>> >> process_flag(trap_exit, true) and then kill Child, receive its exit
>> >> message, set trap_exit to false again (I'm assuming it was false), and
>> >> finally check if there were other exit messages (suiciding if it was
>> >> the case).
>> >>
>> >> But then the code would become too ugly, so I got lazy and decided to
>> >> post to this list.  :-)
>> >>
>> >> What do you think?
>> >>
>> >> Thanks.
>> >> Igor.
>> >> _______________________________________________
>> >> erlang-questions mailing list
>> >> [hidden email]
>> >> http://erlang.org/mailman/listinfo/erlang-questions
>> >
>> >
>
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Raimo Niskanen-2
In reply to this post by mazenharake
On Wed, May 25, 2011 at 09:28:31AM +0200, Mazen Harake wrote:

> Perhaps something like this:
>
> process_flag(trap_exit, true),
> Parent = self(),
> Child = spawn_link(fun() -> Parent ! (catch Op) end),
> receive
>   {'EXIT', ParentsParent, Reason} ->
>     exit(Reason);
>   Result ->
>     Result
>  after N ->
>     unlink(Child),
>     exit(Child, timeout),
>     timeout
> end.

Can the parent always have trap_exit true?

If so this becomes (rather) simple:

  process_flag(trap_exit, true),
  ,
  ,
  Parent = self(),
  Ref = make_ref(),
  Child = spawn_link(fun() -> Parent ! {Ref,Op()} end),
  receive
    {'EXIT',Child,Reason} ->
      receive
        {Ref,Result} ->
          {ok,Result}
      after 0 ->
        {error,Reason}
      end;
  after N ->
    exit(Child, timeout),
      receive
        {'EXIT',Child,timeout} ->
          receive
            {Ref,Result} ->
              {ok,Result}
          after 0 ->
            timeout
          end
      end
  end

If you have no control over the parent trap_exit flag I see
no other alternative than involving a third process.

Note that when a linked process exits normally, the link
causes no exit at the other end.

You maybe should think about using supervisers
and all the other heavy OTP stuff. It was designed for
this kind of problems.



>
> if you get an exit signal from the parent's parent you will exit if you are
> in the receive clause and you will ignore it (unless it is a kill) if you
> are in between the unlink and exit child?
>
> I do however still think that this is very defensive and that the
> probability of getting an exit between unlink and exit is very small unless
> the timeout in N is exactly the same (very very close to) the timeout that
> the parent's parent has for exiting the parent.
>
>
>
> On 25 May 2011 08:51, Igor Ribeiro Sucupira <[hidden email]> wrote:
>
> > Supposing someone used the same logic (with timeout/kill) to spawn the
> > parent process, the parent could be killed at any moment (but yeah: it
> > would be bad luck to have that happening right after it called
> > unlink).
> >
> > Thanks.
> > Igor.
> >
> > On Wed, May 25, 2011 at 3:20 AM, Mazen Harake <[hidden email]>
> > wrote:
> > > Why would someone "kill the parent"? Do you have processes which are
> > > randomly choosing other processes to terminate? ;)
> > >
> > > If your answer is "No" then I would suggest that you just kill the worker
> > > processes that is taking to long, kill it in cold blood, imo.
> > >
> > > There is no reason to think about too many "if"-scenarios when the
> > scenarios
> > > are too far fetched. Try the simple version first :)
> > >
> > > otherwise you can either trap_exits or use monitors instead.
> > >
> > > /M
> > >
> > > On 25 May 2011 08:00, Igor Ribeiro Sucupira <[hidden email]> wrote:
> > >>
> > >> Suppose there is a heavy operation Op that in some cases takes so long
> > >> to finish that the caller loses interest in the result and gives up.
> > >>
> > >> I want to perform that operation in a way that allows me to:
> > >> 1) Interrupt its execution if it does not finish in N milliseconds.
> > >> 2) Interrupt its execution if the calling process exits (here I'm
> > >> already supposing Op has to be run in another Erlang process, due to
> > >> goal 1).
> > >>
> > >> To implement that, it seems unidirectional linking would be needed. Is
> > >> there another safe and convenient way to do it?
> > >>
> > >> The first idea I had was something like this:
> > >>
> > >> Parent = self(),
> > >> Child = spawn_link(fun() -> Parent ! (catch Op) end),
> > >> receive Result -> Result
> > >> after N -> unlink(Child), exit(Child, timeout), timeout
> > >> end.
> > >>
> > >> But, if Parent is killed by another process right after calling
> > >> unlink, Child would be left executing.
> > >> Another problem is that I don't want Parent to die if Child exits for
> > >> non-timeout reasons (although it seems very unlikely in the code
> > >> above, with the catch).
> > >>
> > >> I was now thinking of substituting unlink(Child) with
> > >> process_flag(trap_exit, true) and then kill Child, receive its exit
> > >> message, set trap_exit to false again (I'm assuming it was false), and
> > >> finally check if there were other exit messages (suiciding if it was
> > >> the case).
> > >>
> > >> But then the code would become too ugly, so I got lazy and decided to
> > >> post to this list.  :-)
> > >>
> > >> What do you think?
> > >>
> > >> Thanks.
> > >> Igor.
> > >> _______________________________________________
> > >> erlang-questions mailing list
> > >> [hidden email]
> > >> http://erlang.org/mailman/listinfo/erlang-questions
> > >
> > >
> >

> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions


--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Unidirectional linking?

Igor Ribeiro Sucupira
Well... I'm using something like the last code I posted (with a third
process that creates two monitors) and it's working fine so far.

As for supervision trees, I use them for some cases (usually for
processes that run indefinitely, which I spawn as gen_servers), mostly
because I don't see how they "fit" in the other cases (e.g. in this
discussion).
But maybe I just need to have a better look at supervisors. I got
"Erlang and OTP in Action" from a friend for my birthday. It could be
the opportunity.  :)

Thank you.
Igor.

On Wed, May 25, 2011 at 6:45 AM, Raimo Niskanen
<[hidden email]> wrote:

> On Wed, May 25, 2011 at 09:28:31AM +0200, Mazen Harake wrote:
>> Perhaps something like this:
>>
>> process_flag(trap_exit, true),
>> Parent = self(),
>> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>> receive
>>   {'EXIT', ParentsParent, Reason} ->
>>     exit(Reason);
>>   Result ->
>>     Result
>>  after N ->
>>     unlink(Child),
>>     exit(Child, timeout),
>>     timeout
>> end.
>
> Can the parent always have trap_exit true?
>
> If so this becomes (rather) simple:
>
>  process_flag(trap_exit, true),
>  ,
>  ,
>  Parent = self(),
>  Ref = make_ref(),
>  Child = spawn_link(fun() -> Parent ! {Ref,Op()} end),
>  receive
>    {'EXIT',Child,Reason} ->
>      receive
>        {Ref,Result} ->
>          {ok,Result}
>      after 0 ->
>        {error,Reason}
>      end;
>  after N ->
>    exit(Child, timeout),
>      receive
>        {'EXIT',Child,timeout} ->
>          receive
>            {Ref,Result} ->
>              {ok,Result}
>          after 0 ->
>            timeout
>          end
>      end
>  end
>
> If you have no control over the parent trap_exit flag I see
> no other alternative than involving a third process.
>
> Note that when a linked process exits normally, the link
> causes no exit at the other end.
>
> You maybe should think about using supervisers
> and all the other heavy OTP stuff. It was designed for
> this kind of problems.
>
>
>
>>
>> if you get an exit signal from the parent's parent you will exit if you are
>> in the receive clause and you will ignore it (unless it is a kill) if you
>> are in between the unlink and exit child?
>>
>> I do however still think that this is very defensive and that the
>> probability of getting an exit between unlink and exit is very small unless
>> the timeout in N is exactly the same (very very close to) the timeout that
>> the parent's parent has for exiting the parent.
>>
>>
>>
>> On 25 May 2011 08:51, Igor Ribeiro Sucupira <[hidden email]> wrote:
>>
>> > Supposing someone used the same logic (with timeout/kill) to spawn the
>> > parent process, the parent could be killed at any moment (but yeah: it
>> > would be bad luck to have that happening right after it called
>> > unlink).
>> >
>> > Thanks.
>> > Igor.
>> >
>> > On Wed, May 25, 2011 at 3:20 AM, Mazen Harake <[hidden email]>
>> > wrote:
>> > > Why would someone "kill the parent"? Do you have processes which are
>> > > randomly choosing other processes to terminate? ;)
>> > >
>> > > If your answer is "No" then I would suggest that you just kill the worker
>> > > processes that is taking to long, kill it in cold blood, imo.
>> > >
>> > > There is no reason to think about too many "if"-scenarios when the
>> > scenarios
>> > > are too far fetched. Try the simple version first :)
>> > >
>> > > otherwise you can either trap_exits or use monitors instead.
>> > >
>> > > /M
>> > >
>> > > On 25 May 2011 08:00, Igor Ribeiro Sucupira <[hidden email]> wrote:
>> > >>
>> > >> Suppose there is a heavy operation Op that in some cases takes so long
>> > >> to finish that the caller loses interest in the result and gives up.
>> > >>
>> > >> I want to perform that operation in a way that allows me to:
>> > >> 1) Interrupt its execution if it does not finish in N milliseconds.
>> > >> 2) Interrupt its execution if the calling process exits (here I'm
>> > >> already supposing Op has to be run in another Erlang process, due to
>> > >> goal 1).
>> > >>
>> > >> To implement that, it seems unidirectional linking would be needed. Is
>> > >> there another safe and convenient way to do it?
>> > >>
>> > >> The first idea I had was something like this:
>> > >>
>> > >> Parent = self(),
>> > >> Child = spawn_link(fun() -> Parent ! (catch Op) end),
>> > >> receive Result -> Result
>> > >> after N -> unlink(Child), exit(Child, timeout), timeout
>> > >> end.
>> > >>
>> > >> But, if Parent is killed by another process right after calling
>> > >> unlink, Child would be left executing.
>> > >> Another problem is that I don't want Parent to die if Child exits for
>> > >> non-timeout reasons (although it seems very unlikely in the code
>> > >> above, with the catch).
>> > >>
>> > >> I was now thinking of substituting unlink(Child) with
>> > >> process_flag(trap_exit, true) and then kill Child, receive its exit
>> > >> message, set trap_exit to false again (I'm assuming it was false), and
>> > >> finally check if there were other exit messages (suiciding if it was
>> > >> the case).
>> > >>
>> > >> But then the code would become too ugly, so I got lazy and decided to
>> > >> post to this list.  :-)
>> > >>
>> > >> What do you think?
>> > >>
>> > >> Thanks.
>> > >> Igor.
>
> --
>
> / Raimo Niskanen, Erlang/OTP, Ericsson AB
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions