Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

killing threads inside forks

by mojo2405 (Acolyte)
on Jul 31, 2013 at 08:17 UTC ( [id://1047203]=perlquestion: print w/replies, xml ) Need Help??

mojo2405 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I have a code now that starts fork (with few childs). Each child runs few threads. What I want to do is to - catch a ctrl + c from user by the parent (this part is working for me) , send a signal to the children that kills immediatly the threads and do some more code (write to DB, etc..) - this part is half working for me. the part that working is the children actually catches the signal ( I'm using USR1 signal ) , and hte part that doesnt work for me - us that it catches it only when the threads end. if not threads run in the fork children - the form catches the signal immediatly. Any ideas guys ? this is how I send the USR1 to children : kill USR1 => (keys %framework_child_procs); thanks !

Replies are listed 'Best First'.
Re: killing threads inside forks
by rjt (Curate) on Jul 31, 2013 at 14:21 UTC

    Since you haven't shown your code for how you're handling the signals, I can only hazard a guess. The OS SIGUSR1 comes to each child process' main thread (because that's how it works). Then the child process in turn does a $thread->kill() on each of your threads. So far so good?

    See threads:

    sending a signal to a thread does not disrupt the operation the thread is currently working on: The signal will be acted upon after the current operation has completed. For instance, if the thread is stuck on an I/O call, sending it a signal will not cause the I/O call to be interrupted such that the signal is acted up immediately.

    The good news is, there's a simple answer to the question of how to send signals to threads: don't. It's unreliable at best, and even if it worked, your threads would be in random states. Instead, instrument your threads with their own timeouts (if they're doing blocking operations, that's really where the timeouts belong anyway), and have the threads poll a threads::shared $shutdown variable that's set by your signal handler. Provided you have reasonable timeouts and don't just busy-wait, this is a reasonable use of polling. With the above caveat, remember your child program's main application flow is a thread, too, and subject to the same limitations. When the signal comes in, you give all the threads a few seconds to exit, and if there are still any running, you detach them and exit with a warning.

    bash $ (sleep 1; killall -HUP the_parent) & perl threads.pl [1] 4842 Thread 1: Created Thread 2: Created Thread 3: Created Shutting down 3 threads Thread 1: Shutting down Thread 3: Shutting down 1 still running. Giving up!
      I better be more clearer and show some code.. So this is the father starting his children :
      #Start fork foreach my $xml_obj (@{$xml_ojects_ref}){ my $pid = fork(); if ($pid) { # parent push(@childs, $pid); $framework_child_procs{$pid} = 1; }elsif($pid == 0) { # child my $results = new testProcess($xml_obj,$fatherSN); #Test proce +ss is a new run exit 0; }else { print ,"couldnt fork: $!"; exit 1; } } #Wait for to end foreach my $child (@childs) { my $tmp = waitpid($child, 0); print "done with pid $tmp"; }
      This is the code (inside the father class) , which handles the CTRL+C:
      $SIG{INT}=\&ctrl_c_handler; sub ctrl_c_handler { $SIG{'INT'}='IGNORE'; my @procs = keys (%{fatherProcess::framework_child_procs}); kill SIGUSR1 => @procs; foreach my $child (@procs) { my $tmp = waitpid($child, 0); } }
      This is a code inside a child (this is how I start the threads inside a child actually):
      my $t = threads->new (sub{ local $SIG{'USR1'}=sub {threads->exit();}; \&$functions_name(@parameters); }); my $result = $t->join();
      Now the signal (CTRL+C) comes from the user / CLI , then it catched by the father (going to ctrl_c_handler function) , and then ctrl_c_handler function suppose to send the USR1 signal to the threads - but the thread doesn't catch it. In addition - in the child (testProcess), before starting the thread , I have another USR1 handler , which caught - only after the thread is ending. I think your solution is not suitable here.. please help :)

        Hello mojo2405! Thank you for posting the additional details.

        Now the signal (CTRL+C) comes from the user / CLI , then it catched by the father (going to ctrl_c_handler function) , and then ctrl_c_handler function suppose to send the USR1 signal to the threads - but the thread doesn't catch it. In addition - in the child (testProcess), before starting the thread , I have another USR1 handler , which caught - only after the thread is ending.

        The approach you're taking certainly will not work, because I don't see any evidence in your child process code that you are catching SIGUSR1 in the main thread and re-sending it to all of your threads one by one, as covered in threads:

        Catching signals

        Signals are caught by the main thread (thread ID = 0) of a script. Therefore, setting up signal handlers in threads for purposes other than THREAD SIGNALLING as documented above will not accomplish what is intended.

        This is especially true if trying to catch SIGALRM in a thread. To handle alarms in threads, set up a signal handler in the main thread, and then use THREAD SIGNALLING to relay the signal to the thread:

        mojo2405 wrote:
        I think your solution is not suitable here..

        Oh? Why is that? The one bit of code you have not shown or described is the code that actually runs in your thread (i.e., functions_name()). And, from what you've posted, your child process starts a single thread, waits for that thread to finish, and exits. Why do you even need threads at all? And why can't your threads exit based on polling a shutdown flag instead of a (fake) signal (which, by the way, is implemented via a glorified polling mechanism itself!)

        please help :)

        Believe me, I'm trying. :-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1047203]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2024-04-23 20:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found