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

Re^3: killing threads inside forks

by rjt (Deacon)
on Jul 31, 2013 at 20:52 UTC ( #1047312=note: print w/replies, xml ) Need Help??

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

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. :-)

Replies are listed 'Best First'.
Re^4: killing threads inside forks
by mojo2405 (Acolyte) on Aug 01, 2013 at 07:43 UTC
    Hey rjt ! thank you for your fast answers ! I though I wouldn't need to do so , but I have to expose my code, maybe I'll be clearer. I want to thank you first for your help , I know you're trying :) First I want to say that my code can't have any timeout, cause it can be running for days or even weeks, so timeout for the threads is not useful here. I tried to add an alarm trigger for the children , but still - same problem. Now , for the code , there is alot of code so I'll try to show what is relevant for our case and cut some of it. Father :
    sub init { my ($logger_input,$xmlFile_input,$ini_file_input,$run_all_input,$g +ui_sync_file_input,$dump_input) = @_; #Setting and reading params from run_me readParamsFromRunme($logger_input,$xmlFile_input,$ini_file_input,$ +run_all_input,$gui_sync_file_input,$dump_input); #Handle Ctrl+c if not running via GUI $SIG{INT}=\&ctrl_c_handler if (!$gui_sync_file); ##kill -10 from UI $SIG{USR1}=\&usr_kill_handler; } # FUNCTION NAME: ctrl_c_handler # WRITTEN BY: Sagi # DATE: 1.11.2011 # PURPOSE: Exit the test when user press Ctrl+c # IN PARAMS: None # RETURNED VALUES: None # Sample call: sub ctrl_c_handler { #Wait for to end $SIG{'INT'}='IGNORE'; my @procs = keys (%{fatherProcess::framework_child_procs}); kill ALRM => @procs; kill SIGUSR1 => @procs; foreach my $child (@procs) { my $tmp = waitpid($child, 0); } $father_self->finishRun("user stoped"); } sub usr_kill_handler { my $signame = shift; printer::Logger_screen_message("info","got signal $signame",0,$log +ger); $father_self->finishRun("user stoped"); }
    Start forking the childs from the father :
    sub start_fork_run{ my $self = shift; my ($xml_ojects_ref,$night_run_flag) = @_; my @childs = (); #Get father PID my $father_pid=$$; #Get father SN my $fatherSN = $self->getSN(); if (!$fatherSN){ printer::Logger_screen_message("error","can't get father's SN from + DB",0,$logger); exit 1; } #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,$gui_sync_fil +e,$father_pid,$night_run_flag); exit 0; }else { printer::Logger_screen_message("error","couldnt fork: $!",0,$l +ogger); exit 1; } } #Wait for to end foreach my $child (@childs) { my $tmp = waitpid($child, 0); delete $framework_child_procs{$child}; printer::Logger_screen_message("info","done with pid $tmp",0,$logg +er); } #End the whole topology run $self->finishRun("finish"); }
    a child object :
    package testProcess; #use strict; use warnings; use Data::Dumper; use Getopt::Long; use File::Basename; use File::Temp; use Storable ('dclone'); use logger; use reporter; my $logger; our $local_xml_obj; my $gui_sync_file; my $night_run; my $packageReporter; sub new { my $class = shift; my ($xml_obj,$fatherSN,$gui_sync_file_input,$father_pid,$night_run +_input) = @_; #kill -10 from UI $SIG{'USR1'}=\&prc_kill_handler; #Reseting signals so only father will catch them $SIG{'INT'}='IGNORE'; $SIG{'ALRM'}=sub {foreach my $thr (@parallel::threads){ $thr->kill('ALRM'); } }; } sub prc_kill_handler { my $signame = shift; printer::colorized_msg("\n got to prc_kill_handler \n","green"); $logger->info("usr_kill_handler: got signal $signame line: ".__LIN +E__); testProcess::finishPackage("user stoped"); testProcess::exit_run(); }
    now each child can call this parallel function (which create threads as many as he wishes) , and here is the problem (that it catches the signal only after the threads end) :
    sub Functions_Run_in_threads_windows { my (%hash)=@_; printer::Logger_screen_message ("Info", "Start", "", $logger); my @temp_file; if(!%hash) { printer::Logger_screen_message("Error","Functions_Run_in_threads +: The hash is empty",1,$logger); return %hash; } my ($functions_name,@temp_params,@parameters,%hash_results); @threads = (); for( my $i=0 ; $hash{"params_name_$i"} ; $i++) { @temp_params=$hash{"params_name_$i"}; $functions_name=$hash{"function_name_$i"}; @parameters=(); #push (@parameters,$functions_name); if(!@{$temp_params[0]}) #check input if not reference return fai +l { printer::Logger_screen_message("Error","Please send parameter +s array as referens",1,$logger); return %hash; } #parse hash table and run the function for( my $index=0 ; $index<@{$temp_params[0]} ; $index++) { if($temp_params[0][$index]) { $tmp=$temp_params[0][$index]; push(@parameters,$tmp); } else { push(@parameters,""); } } #Start new thread my $t = threads->create (sub{ $SIG{ALRM} = sub { die("Timeout\n"); }; \&$functions_name(@parameters); }); 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++; } return %hash_results; }
    Hope now you better understand it (and the problem). Thanks again.

      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.


      • Do you just want the entire child process to 'go away' silently?
      • Do you want the child threads to 'go away' silently, but the child's main thread to continue to run?
      • Do you want the child threads to perform some final processing (perhaps returning some data to the main thread) before terminating, and then the child's main thread to do some final processing before terminating?

      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.
        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...

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1047312]
[Corion]: Whee! Germanys Grand Central Airport (for Berlin, re-scheduled for the thrid or fourth time, to open now in 2018) has just fired their technical lead
[ambrus]: Corion: Is their budget estimate four times the initial estimate yet? Was the construction late by six months already three months after they started?
[marto]: I'll believe it when I see it. That's been due for many years now :P
[marto]: oddly the last time I was there I saw a zeppelin in flight for the first time
[Corion]: ambrus: I don't know how far the budget estimate has been overrun yet
[Corion]: marto: Heh ;) No, you were likely at Tegel or Schönefeld, the new one ("BER") will be somewhat outside of Berlin ;)

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (10)
As of 2017-02-23 11:56 GMT
Find Nodes?
    Voting Booth?
    Before electricity was invented, what was the Electric Eel called?

    Results (346 votes). Check out past polls.