在Java中,当我创建线程并共享一个对象时,我有时会希望线程访问相同的对象方法,但我不知道它们是什么时候同时执行它。因此,为了避免这种情况,我将对象方法定义为Synchronized方法,如下所示。
同步实例方法:
class class_name { synchronized type method_name(){ \声明块 } }
方法中的所有语句都成为synchronized块,而实例对象是锁。这意味着如果我告诉一个线程使用这个方法,它将等到前一个线程完成使用该方法。 有没有办法在Perl中执行此操作?
答案 0 :(得分:5)
在构造函数中创建一个互斥锁。
sub new {
...
my $mutex :shared;
$self->{mutex_ref} = \$mutex;
...
}
输入方法时锁定它。
sub method {
my ($self) = @_;
lock ${ $self->{mutex_ref} };
...
}
演示:
use strict;
use warnings;
use threads;
use threads::shared;
use feature qw( say );
sub new {
my ($class, $id) = @_;
my $mutex :shared;
return bless({
mutex_ref => \$mutex,
id => $id,
}, $class);
}
sub method {
my ($self) = @_;
lock ${ $self->{mutex_ref} };
say sprintf "%08X %s %s", threads->tid, $self->{id}, "start";
sleep(2);
say sprintf "%08X %s %s", threads->tid, $self->{id}, "end";
}
my $o1 = __PACKAGE__->new('o1');
my $o2 = __PACKAGE__->new('o2');
for (1..3) {
async { my ($o) = @_; $o->method() } $o1;
async { my ($o) = @_; $o->method() } $o2;
}
$_->join for threads->list();
$o1->method
的电话。$o1->method
和$o2->method
的通话可以同时进行。实际上,如果你打算共享对象 - 这是通过将对象作为参数传递给async
int上面的代码完成的 - 你可以使用对象本身作为锁。
use threads::shared qw( shared_clone );
sub new {
my ($class, ...) = @_;
return shared_clone(bless({
...
}, $class));
}
输入方法时锁定它。
sub method {
my ($self) = @_;
lock %$self;
...
}
答案 1 :(得分:2)
您可以使用semaphores在线程之间发出信号,或者在调用相关方法时使用lock共享对象,导致其他线程的任何后续调用都会阻塞,直到锁定线程完成该方法调用
在开始使用perl进行线程化之前,我强烈建议您阅读perl thread tutorial,因为perl的线程与其他语言不同
答案 2 :(得分:0)
旧的perl线程模型(来自5.005)支持属性:locked
,或多或少可以满足您的需求。但是,对于当前的 ithreads 模型(5.8以后),您可以重新引入类似的属性。
这基本上是@ ikegami的simplified solution,隐藏在Attribute::Handlers的句法方便之后:
package Local::Sub::Attribute::Synchronized;
use strict;
use warnings;
use thread::shared;
use Attribute::Handler;
sub Synchronized : ATTR(CODE) {
my (undef, $sym, $code) = @_;
#
# Lock the first argument (assumed to be a shared() object), then call $code
# with the original @_
#
no warnings 'redefine';
*{$sym} = sub { lock($_[0]); &$code; };
}
sub import { # Make :Synchronized available to our importer.
my $callpkg = caller; # The usual technique is defines a UNIVERSAL::
no strict 'refs'; # handler, but I find that a bit ham-fisted.
push @{"${callpkg}::ISA"}, __PACKAGE__;
}
允许你像这样编写你的课程:
package Foo;
use threads::shared;
use Local::Sub::Attribute::Synchronized;
sub new { shared_clone(...); } # N.B.: Your Foo object must be shared!
sub method_name : Synchronized {
...
}
你的代码是这样的:
$foo_object->method_name(); # Don't worry, it's synchronized!