我正在尝试启动一个可以随时暂停/恢复的线程。以下是我创建线程的方法:
use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Suspend;
use Thread::Semaphore;
sub createThread {
my $semaphore = Thread::Semaphore->new();
my $thr = threads->create(sub {
local $SIG{KILL} = sub {
die "Thread killed\n";
};
local $SIG{STOP} = sub {
print "sig stop\n";
$semaphore->down();
};
local $SIG{CONT} = sub {
$semaphore->up();
print "sig cont\n";
};
my $test = sub {
while (1) {
$semaphore->down();
print STDERR "Working process\n";
sleep(2);
$semaphore->up();
}
};
return $test->();
});
return $thr->tid();
}
检索线程ID后(使用return $thr->tid();
)。然后我尝试暂停它,并且正在打印消息sig stop
,稍后当我尝试恢复它时sig cont
不打印。这是暂停/恢复线程的代码:
sub pause {
my $class = shift;
my $threadId = shift;
my $thr = threads->object($threadId);
if ($thr) {
if ($thr->is_suspended() == 0) {
$thr->kill('STOP');
$thr->suspend();
return "Process $threadId paused\n";
} else {
return "Process $threadId has to be resumed\n";
}
} else {
return "Process $threadId not found\n";
}
}
sub resume {
my $class = shift;
my $threadId = shift;
my $thr = threads->object($threadId);
if ($thr) {
if ($thr->is_suspended() != 0) {
$thr->resume();
$thr->kill('CONT');
return "Operation $threadId resumed\n";
} else {
return "Operation $threadId has not been paused\n";
}
} else {
return "Process $threadId not found\n";
}
}
我恢复暂停的线程后,消息Operation X was resumed
但sig cont
没有,并且线程功能也没有恢复。
答案 0 :(得分:5)
目前还不清楚您是否需要Thread::Semaphore
用于单独目的,但Thread::Suspend
我怀疑你的暂停/恢复无效的原因是你已经覆盖Thread::Suspend
为自己的目的设置的信号处理程序
如果我删除所有信号处理程序和Thread::Semaphore
内容,那么您的代码可以正常运行:
use strict;
use warnings 'all';
use threads;
use Thread::Suspend;
STDOUT->autoflush;
my $tid = create_thread();
for ( 1 .. 10 ) {
sleep 5;
print pause($tid);
sleep 5;
print resume($tid);
}
sub create_thread {
my $thr = threads->create( sub {
while () {
print "Working thread\n";
sleep 1;
}
} );
return $thr->tid;
}
sub pause {
my ($tid) = @_;
my $thr = threads->object($tid);
return "Thread $tid not found\n" unless $thr;
return "Thread $tid is already suspended\n" if $thr->is_suspended;
$thr->suspend;
return "Thread $tid paused\n";
}
sub resume {
my ($tid) = @_;
my $thr = threads->object($tid);
return "Thread $tid not found\n" unless $thr;
return "Thread $tid has not been paused\n" unless $thr->is_suspended;
$thr->resume;
return "Thread $tid resumed\n";
}
Working thread
Working thread
Working thread
Working thread
Working thread
Thread 1 paused
Thread 1 resumed
Working thread
Working thread
Working thread
Working thread
Working thread
Thread 1 paused
Thread 1 resumed
Working thread
Working thread
...
您的子程序也不需要。这是一个简单的实现
use strict;
use warnings 'all';
use threads;
use Thread::Suspend;
STDOUT->autoflush;
sub thread_sub {
while () {
printf "Working thread %d\n", threads->self->tid;
sleep 1;
}
}
my $thr = threads->create(\&thread_sub);
for ( 1 .. 10 ) {
sleep 5;
if ( my $suspended = $thr->suspend ) {
printf "Thread %d suspended\n", $suspended->tid;
}
sleep 5;
if ( my $resumed = $thr->resume ) {
printf "Thread %d resumed\n", $resumed->tid;
}
}
Working thread 1
Working thread 1
Working thread 1
Working thread 1
Working thread 1
Working thread 1
Thread 1 suspended
Thread 1 resumed
Working thread 1
Working thread 1
Working thread 1
Working thread 1
Working thread 1
Working thread 1
Thread 1 suspended
Thread 1 resumed
Working thread 1
Working thread 1
Working thread 1
答案 1 :(得分:4)
这里没有使用实际信号。信号只能发送到进程,而不是线程。来自$thread->kill
的文档:
CAVEAT:该模块提供的线程信令功能实际上并不通过OS发送信号。它模拟Perl级别的信号,以便在适当的线程中调用信号处理程序。例如,发送
$thr->kill('STOP')
实际上不会挂起线程(或整个进程),但会导致在该线程中调用$SIG{'STOP'}
处理程序(如上所示)。
由于此处未使用实际信号,因此您不会混合信号和线程。好。
但这是一个过于复杂的设计。只需拨打$sem->down_force()
中的pause
和$sem->up()
中的resume
即可。在线程中不需要这样做。
use strict;
use warnings;
use threads;
use Thread::Semaphore qw( );
{
package Worker;
sub new {
my $class = shift;
return bless({ @_ }, $class);
}
sub thr { return $_[0]{thr} }
sub tid { return $_[0]{thr}->tid() }
sub join { $_[0]{thr}->join() }
sub pause { $_[0]{sem}->down_force() }
sub resume { $_[0]{sem}->up() }
}
sub createThread {
my $sem = Thread::Semaphore->new();
my $thr = async {
while (1) {
$sem->down();
...
$sem->up();
}
};
return Worker->new( thr => $thr, sem => $sem );
}
sub pause { my ($worker) = @_; $worker->pause(); }
sub resume { my ($worker) = @_; $worker->resume(); }
当然,这假设您只想暂停工作单元之间的线程。如果你想立即暂停线程,你就不需要信号量或信号"在所有 [1] 。
use strict;
use warnings;
use threads;
use Thread::Suspend; # Must call import!
{
package Worker;
sub new {
my $class = shift;
return bless({ @_ }, $class);
}
sub thr { return $_[0]{thr} }
sub tid { return $_[0]{thr}->tid() }
sub join { $_[0]{thr}->join() }
sub pause { $_[0]{suspended}++ || $_[0]{thr}->suspend() }
sub resume { --$_[0]{suspended} || $_[0]{thr}->resume() }
}
sub createThread {
my $thr = async {
...
};
return Worker->new( thr => $thr );
}
sub pause { my ($worker) = @_; $worker->pause(); }
sub resume { my ($worker) = @_; $worker->resume(); }
奖励:$worker->pause; $worker->pause; $worker->resume; $worker->resume;
适用于这两种方法(与问题中的版本不同)。
如果你想继续使用tid而不是对象,只需将对象存储在由tid键入的哈希值中。