Does anyone have experience in how to handle signals in threaded program? Many thanks.

M

mike

Let's see sample1.pl first. In sample1.pl, there is no signal
capturing.

#!/usr/bin/perl
# sample1.pl
use threads;

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;
while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->join;
$thr2->join;

sample1.pl exited immediately when it captured SIGUSR1.
Here is the output:

pid = 14094
1 run once...
2 run once...
1 run once...
2 run once...
User defined signal 1

It is easy to understand that the process just performed the default
signal response action and didn't care about the threads.

Let's see sample2.pl. It has signal capturing defined in the thread.

#!/usr/bin/perl
# sample2.pl
use threads;

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;

$SIG{USR1}= sub { print "got signal.\n"; };

while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->join;
$thr2->join;

sample2.pl also exited immediately when it captured SIGUSR1, just as
not defined.
Here is the output:
pid = 14275
1 run once...
2 run once...
1 run once...
2 run once...
User defined signal 1

Question 1: Which thread captured the SIGUSR1? or just the process
captured the SIGUSR1?
Question 2: Why did the program NOT printing "got signal"? seems the
subroutine doesn't work.

In sample3.pl, I defined the signal capture outside of the thread.

#!/usr/bin/perl
# sample3.pl
use threads;

$SIG{USR1}= sub { print "got signal.\n"; };

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;

while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->join;
$thr2->join;

When I sent SIGUSR1 to the process, no any actions were performed, and
I finally had to kill the process.

Question 3: Why did the program not capture the signal? seems the join
method is suspicious.

Let's see the last sample4.pl. I replaced the join method with detach,
and also made some other changes regarding the detach.

#!/usr/bin/perl
# sample4.pl
use threads;

my $exit;
$SIG{USR1}= sub { print "got signal.\n"; $exit++;};

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;

while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->detach;
$thr2->detach;

while(!$exit) { sleep 1; }

When sample4.pl captured SIGUSR1, it acted just as I expected. Here is
the output:

pid = 14541
1 run once...
2 run once...
1 run once...
2 run once...
got signal.
A thread exited while 3 threads were running.

Quetion 4: What is the difference between join and detach when the
process/threads handle signal?
Quetion 5: Is it possible that the main process capture the signal and
then send the signal to all threads? How?
Quetion 6: I wanna code a program that has multiple threads, each
thread has its own task. Each thread is capable to capture specific
signal to perform specific job, for example, clean up and exit while
captured SIGUSR2. I wonder if any of you guys can write me a sample
code demonstrating how to capture signal in thread.

I will really appreciate your help, and many thanks for your patience
to read this posting.
 
X

xhoster

mike said:
Let's see sample2.pl. It has signal capturing defined in the thread.

#!/usr/bin/perl
# sample2.pl
use threads;

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;

$SIG{USR1}= sub { print "got signal.\n"; };

while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->join;
$thr2->join;

sample2.pl also exited immediately when it captured SIGUSR1, just as
not defined.
Here is the output:
pid = 14275
1 run once...
2 run once...
1 run once...
2 run once...
User defined signal 1

Question 1: Which thread captured the SIGUSR1?

The "main" thread, i.e. the one that was waiting on the join. Which
didn't have a sig handler in place.
or just the process
captured the SIGUSR1?

I don't understand how threading works under the hood, but in some respects
you can say that the main thread *is* the process.
Question 2: Why did the program NOT printing "got signal"? seems the
subroutine doesn't work.

Because the thread that got the signal did not have a sig handler in place.

In sample3.pl, I defined the signal capture outside of the thread.

#!/usr/bin/perl
# sample3.pl
use threads;

$SIG{USR1}= sub { print "got signal.\n"; };

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;

while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->join;
$thr2->join;

When I sent SIGUSR1 to the process, no any actions were performed, and
I finally had to kill the process.

Question 3: Why did the program not capture the signal?

It did get the signal, at the "perl" level (the program written in C which
implements Perl). It just didn't do anything visible with it at the "Perl"
level (the level at which the typical programmer programs in Perl). If you
set the environment variable PERL_SIGNALS to "unsafe", you would probably
get the behavior you expected, unless you got a seg-fault instead.
seems the join
method is suspicious.

Under "safe" signals, the sig-handler is deferred until it is "safe" to
execute it. Apparently, this means until after the "join" completes.
Since the "join" never completes, the sig-handler is never run.

Let's see the last sample4.pl. I replaced the join method with detach,
and also made some other changes regarding the detach.

#!/usr/bin/perl
# sample4.pl
use threads;

my $exit;
$SIG{USR1}= sub { print "got signal.\n"; $exit++;};

$thr1 = new threads \&sample_sub, 1;
$thr2 = new threads \&sample_sub, 2;

print "pid = $$\n";

sub sample_sub {
my $SubNumber = shift @_;

while (1) {
print "$SubNumber run once...\n";
sleep(4);
}
}

$thr1->detach;
$thr2->detach;

while(!$exit) { sleep 1; }

When sample4.pl captured SIGUSR1, it acted just as I expected. Here is
the output:

pid = 14541
1 run once...
2 run once...
1 run once...
2 run once...
got signal.
A thread exited while 3 threads were running.

Quetion 4: What is the difference between join and detach when the
process/threads handle signal?

It is not the difference between join and detach, it is the difference
between join and sleep.

Quetion 5: Is it possible that the main process capture the signal and
then send the signal to all threads? How?
Quetion 6: I wanna code a program that has multiple threads, each
thread has its own task. Each thread is capable to capture specific
signal to perform specific job, for example, clean up and exit while
captured SIGUSR2. I wonder if any of you guys can write me a sample
code demonstrating how to capture signal in thread.

I wouldn't touch that with a ten foot pole. If need be, I'd use separate
processes, rather than threads.

Xho
 
M

mike

Thanks a lot first for your reply.
Regarding your words "Because the thread that got the signal did not
have a sig handler in place.", I defined signal handler in thread in
sample2.pl, how come the signal was not captured? Maybe there are some
other ways to define signal handler and capture signal in thread.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top