http://www.perlmonks.org?node_id=1047395


in reply to Re^4: killing threads inside forks
in thread killing threads inside forks

Signals won't interrupt a kernel wait state. join() is a kernel wait state.

my $index=0; foreach my $thread (@threads) #wait for all threads until the end +and insert results to hash { $hash_results{$index}=$thread->join; $index++; } return %hash_results;

Signals and threads do not mix well anywhere.

If you would describe in words, what you want to happen to the child process and its threads when your parent process decides it is time for that something to happen -- without describing the process by which the parent notifies the child, or how the child receives the notification -- then there is probably a good mechanism for doing it, that does not require sticking a spanner in the spokes to get the wheels to stop turning.

Ie:

Until you tell us what you want to do, rather than repeating over and over how you think you ought to do it -- which clearly doesn't work; and probably never will -- there is little we can do beyond keep telling you that what you are trying to do doesn't work.

Which you already know because that's why you came here.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re^6: killing threads inside forks
by mojo2405 (Acolyte) on Aug 01, 2013 at 13:59 UTC
    Actually you are right. I didn't real explained myself. I do want to terminate the threads childs and do some processing afterward (writing to a DB) , and then exit the child (fork) , and then exit the father. I got some answers here - and it really really helped, so thank you for that. I used the shared variable, and manaaged to kill all threads how I wanted. the problem now is that , if I dont kill the thread - I just get a hang , and nothing happens . I just don't know how to signal the sleep that all threads ended succesfully (and I want to join them). here is what I got so far :
    $SIG{USR1} = sub {shutdown = 1;}; foreach my $functions_name (@func_arr){ #Start new thread my $t = threads->create (sub{ &$functions_name(@parameters); $SIG{KILL} = sub { print "\ngot to thread killer\n\n"; threads->exit(); }; print "\ngot to end of thread\n\n"; #$shutdown = 1; }); push(@threads,$t); } sleep until $shutdown; if (my @remain = threads->list(threads::running)) { foreach (@remain) { if ($_ != $$){ $_->kill('KILL')->detach; } } $shutdown = 0; testProcess::prc_kill_handler(); } print "All threads exited normally."; my $index=0; foreach my $thread (@threads) #wait for all threads untill the end +and insert results to hash { $hash_results{$index}=$thread->join; $index++; } return %hash_results;
    Again ,this code actually works good when sending USR1 signal , but it doesn't when I'm not sending any signal , it just reaches to :
    print "\ngot to end of thread\n\n";
    and then nothing happens. how can I handle that ? thanks again guys ! sorry if I'm not so clear again...

      Caution: I cannot test this because I don't have a real fork. But ... there are several problems with your code.

      1. You are only setting the signal handler in your threads after your thread function has completed:
        my $t = threads->create (sub{ ## You run your thread function here &$functions_name(@parameters); ## And when it has completed -- if it ever does -- ## You set up a signal handler ... $SIG{KILL} = sub { print "\ngot to thread killer\n\n"; threads->exit(); }; print "\ngot to end of thread\n\n"; #$shutdown = 1; ## and then exit the thread. });
      2. You avoided the kernel wait problem by sleeping until the signal arrives:
        sleep until $shutdown;

        But sleep with no argument is the same as sleep 0; which means that your main thread is thrashing your cpu to death.

        Update: Thanks to rjt for informing me that Perl implements sleep such that: "or forever if no EXPR."; thus my struck assertion above is wrong.

      3. When you do get a signal in your main thread, you then send a kill to all your threads, and then detach them:
        if ($_ != $$){ $_->kill('KILL')->detach; }

        And then you fall through to join them. Except you cannot join a detached thread.

      4. None of what you are doing makes any sense at because (from the threads pod):
        Correspondingly, 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.
      5. And finally:
        Sending a signal to a terminated thread is ignored.

      So, when you say:

      this code actually works good when sending USR1 signal

      You are wrong. It doesn't "work", it simply breaks your main thread out of the sleep loop. Nothing else.

      The signals you think you are sending your threads are never arriving, because you don;t set up their signal handlers until just before they finish. But even if you correct that; those signals still won;t kill the threads -- because kill signals are ignored -- and if you send some other signal, they threads still won't see it until they've finished whatever they are doing.

      Which might or might not ever happen; I've no way to tell because you keep posting dummy snippets instead of real code; and have still failed to describe what these threads are actually doing.

      I said it earlier, and I'll say it again: signals and threads do not mix.

      (The threads-signals stuff should never have been added to the api it is essentially useless!)

      If you ever post the real code; and a proper description of what your code is actually doing; I might try to help you further; but for now ....


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        Hi, So, I'm attaching my code. The code create 3 sons (with fork). Then each son create 3 grand sons (with thread). What I'm failing to do is to send to a son (started with fork) a USR1 signal , which will make all its grand sons to exit immediatly (and not wait to the grand sons to exit after they finish their work). I want to send the USR1 signal from outside to the son PID. I know there is a limitation and I might can not do that, but do other here another clean way to exit threads of the son immediatly when son gets USR1 signal ? Thanks ! Here is the code , the goal is to make the threads to exit while sleep function starting :
        #!/usr/bin/env perl use threads; ##kill -10 handle $SIG{USR1}=\&usr_kill_handler; my @sons = ("Son1","Son2","Son3"); my @childs = (); #Start fork foreach my $son (@sons){ my $pid = fork(); if ($pid) { # parent push(@childs, $pid); }elsif($pid == 0) { # child my $results = new testProcess($son); exit 0; }else { print "\nerror : couldnt fork: $!\n"; exit 1; } } #Wait for to end foreach my $child (@childs) { my $tmp = waitpid($child, 0); print "\ninfo : done with pid $tmp\n"; } sub usr_kill_handler{ #Send SIGUSR1 to all childs (started with fork) kill SIGUSR1 => @childs; print "\n\n Stoped due to user request!\n\n"; #Wait to all childs to exit foreach my $child (@childs) { my $tmp = waitpid($child, 0); print "\ndone with pid $tmp\n"; } # After all child ended kill father exit 1; } package testProcess; sub new{ my $class = shift; my ($son) = @_; ##kill -10 handle $SIG{USR1}=sub { print "\n Got signal to son $son with pid ".$$." \n"; threads->exit; }; print "\nSon $son with PID ".$$." Started\n"; my %hash_results = (); my @grand_sons = ("Grand son 1","Grand son 2","Grand son 3"); my @threads = (); #Start new thread foreach my $grand_son (@grand_sons){ my $t = threads->create (\&start_threads,$son,$grand_son); push(@threads,$t); } my $index=0; foreach my $thread (@threads) #wait for all threads untill the end + and insert results to hash { $hash_results{$index}=$thread->join; $index++; } print "\nSon $son with PID ".$$." Finished\n"; } sub start_threads{ my ($son,$grand_son) = @_; print "\nSon $son grand son $grand_son started\n"; my $random_number = int(rand(100)); my $msg = "Son $son grand son $grand_son returns random number $ra +ndom_number"; print "\n$msg\n"; sleep 100; return $random_number; } 1;