Perl恢复了一个帖子

时间:2016-07-27 11:22:34

标签: multithreading perl

我正在尝试启动一个可以随时暂停/恢复的线程。以下是我创建线程的方法:

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 resumedsig cont没有,并且线程功能也没有恢复。

2 个答案:

答案 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键入的哈希值中。

  1. 至少,除了Thread :: Suspend之外,它还使用"信号"什么等于内部的信号量。