2

I have code that spawns two threads. The first is a system command which launches an application. The second monitors the program. I'm new to perl threads so I have a few questions...

my $thr1 = threads->new(system($cmd));
sleep(FIVEMINUTES);
my $thr2 = threads->new(\&check);

my $rth1 = $thr1->join();
my $rth2 = $thr2->join();

1) Do I need a second thread to monitor the program? You can think of my sub routine call to &check as a infinite while loop which checks a text file for stuff the application produces. Could I just do this:

my $thr1 = threads->new(system($cmd));
sleep(FIVEMINUTES);
✓

2) I'm trying to figure out what my parent is doing after I run this code. So after I launch line 1 it will spawn that new thread, sleep, then spawn that second thread and then sit at that first join and wait. It will not execute the rest of my code until it joins at that first join. Is this correct or am I wrong? If I am wrong, then how does it work?

3) My first thread the one that launches the application can be killed unexpectedly. when this happens, I have nothing to catch that and kill the threads. It just says: "Thread 1 terminated abnormally: Undefined subroutine &main::65280 called at myScript.pl line 109." and then hangs there.

What could I do to get it to end the other threads? I need it to send an email before the program ends as well which I can do by just calling &email (another subroutine I made).

Thanks

pilcrow
  • 56,591
  • 13
  • 94
  • 135
Ryan
  • 441
  • 1
  • 5
  • 12
  • When `threads->create` isn't given a code reference, but a scalar/string, it will use that string as a subroutine name. When the `system` command exits, it returns an error code. Your problem stems from using this error code (`65280`) as a subroutine name. You need to enclose it in a sub, as ikegami showed in his answer. – amon Jun 21 '13 at 19:59

3 Answers3

4

First of all,

my $thr1 = threads->new(system($cmd));

should be

my $thr1 = threads->new(sub { system($cmd) });

or simply

my $thr1 = async { system($cmd) };

You don't need to start a third thread. As you suspected, the main thread and the one executing system are sufficient.


What if the command finishes executing in less than five minutes? The following replaces sleep with a signal.

use threads;
use threads::shared;

my $done :shared = 0;

my $thr1 = async {
   system($cmd);

   lock($done);
   $done = 1;
   cond_signal($done);
};

{ # Wait up to $timeout for the thread to end.
   lock($done);
   my $timeout = time() + 5*60;
   1 while !$done && cond_timedwait($done, $timeout);
   if (!$done) {
      ... there was a timeout ...
   }
}

$thr1->join();
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Why do I need the sub in there? What does "async" do? Thanks :) – Ryan Jun 24 '13 at 16:39
  • Because that's the usage of `threads->new`. You were executing a `system` before creating the thread, and you had the thread execute a subroutine named by the result of `system` (a number). // `async { system($cmd) }` is the same thing as `threads->new(sub { system($cmd) })`, like I said. – ikegami Jun 24 '13 at 16:45
1

In 2004-2006 I had the same challenges for 24/7 running perl app on Winblows... The only approach working was to use xml state files on disk to communicate the status of each component of the system... and make sure if threads are used every stat file handling occurred within a closure code block {} (big gotcha) The app ran at least 3 years on 100 machines 24/7 without errors ... If you are on a Unix-like OS I would suggest to use forks and interprocess communication. Use cpan modules, do not reinvent the wheel..

Yordan Georgiev
  • 5,114
  • 1
  • 56
  • 53
0

Multithreading in Perl is a little hard to deal with, I would suggest using the fork() commands instead. I will attempt to answer your questions to the best of my ability.

1) It seems to me like two threads/processes are the way to go here, as you need to check asynchronously check your data.

2) Your parent works exactly as you describe.

3) The reason for your thread hanging could be that you never terminate your second thread. You said it was an infinite loop, is there any exit condition?

dakillakan
  • 240
  • 2
  • 9
  • I'm not sure how to use fork() but i'll take a look. 3) Yes there is but it is only set if my application does NOT exit abruptly, which it does frequently. So I need thread2 to notice that my other thread died unexpectedly. Not sure how to do that. Also not sure what the value of $thr1 will be when that happens. – Ryan Jun 21 '13 at 19:13
  • @dakillakan, That's not a bug of threads. (This message will self-destruct) – ikegami Jun 21 '13 at 21:33