bob_saginowski
bob_saginowski

Reputation: 1429

Perl threads don't suspend/ resume

I am using Thread::Suspend to start threads from remote modules. Some of the $subrotine calls take longer than 30 seconds.

my $thr = threads->create(sub {
    capture(EXIT_ANY, $^X, $pathToModule, $subroutine, %arguments)
});
return $thr->tid();

My issue is that I am not able to suspend/resume a created thread. Here is the code execute to suspend a thread:

use IPC::System::Simple qw (capture $EXITVAL EXIT_ANY);
use threads;
use Thread::Suspend; 
use Try::Tiny; 

sub suspendThread {
    my $msg;
    my $threadNumber = shift;

    foreach (threads->list()) {
        if ($_->tid() == $threadNumber) {
            if ($_->is_suspended() == 0) {
                try {
                    # here the execution of the thread is not paused
                    threads->suspend($_);
                } catch {
                    print "error: " . $! . "\n";
                };

                $msg = "Process $threadNumber paused";
            } else {
                $msg = "Process $threadNumber has to be resumed\n";
            }   
        }
    }

    return $msg;
}

And this is the code from the module that I load dynamically:

sub run {
    no strict 'refs';
    my $funcRef = shift;
    my %paramsRef = @_;
    print &$funcRef(%paramsRef);
}

run(@ARGV);

I guess that the problem is that the sub passed to the treads constructor calls capture (from IPC::System::Simple module). I also tried to create the thread with my $thr = threads->create(capture(EXIT_ANY, $^X, $pathToModule, $subroutine, %arguments)); Any ideas how to resolve it.

Upvotes: 1

Views: 160

Answers (1)

ikegami
ikegami

Reputation: 385565

These are the threads you have:

Parent process                  Process launched by capture
+---------------------+         +---------------------+
|                     |         |                     |
|  Main thread        |         |  Main thread        |
|  +---------------+  |         |  +---------------+  |
|  |               |  |         |  |               |  |
|  | $t->suspend() |  |         |  |               |  |
|  |               |  |         |  |               |  |
|  +---------------+  |         |  +---------------+  |
|                     |         |                     |
|  Created thread     |         |                     |
|  +---------------+  |         |                     |
|  |               |  |         |                     |
|  | capture()     |  |         |                     |
|  |               |  |         |                     |
|  +---------------+  |         |                     |
|                     |         |                     |
+---------------------+         +---------------------+

You claim the thread you created wasn't suspended, but you have practically no way of determining whether it was suspended or not. After all, capture does not print anything or change any external variables. In fact, you have no reason to believe it wasn't suspended.

Now, you might want the program you launched to freeze, but you have not done anything to suspend it or its main thread. As such, it will keep on running[1].

If you wanted to suspend an external process, you could send SIGSTOP to it (and SIGCONT to resume it). For that, you'll need the process's PID. I recommend replacing capture with an IPC::Run pump loop.


  1. Well, it will eventually block when it tries to write to STDOUT because the pipe got full because you actually did suspend the thread running capture.

Upvotes: 3

Related Questions