Perl:IPC::Shareable 和 SWIG ed C++对象不同意

发布于 2024-12-06 06:41:01 字数 2564 浏览 2 评论 0原文

对于我的某个 Perl 项目,我需要多个 Perl 进程来共享位于 C++ 库中的一些资源。 (不要问,这不是这个问题的核心,只是上下文。)

因此,我试图深入研究这个上下文中的两个“新”领域:IPC::Shareable,并使用 SWIG 包装 C++。看来我在那里做错了什么,这就是我想问的。


在 C++ 方面,我编写了一个小型测试类 Rectangle,其中包含一个空构造函数、一个 set 和一个 size 成员函数。

然后我将该类包装在 SWIG 生成的 Perl 包 example 中。

在 Perl 方面,我尝试了 SWIG 模块是否按预期工作:

use example;
my $testrec = new example::Rectangle;
$testrec->set( 6, 7 );
print $testrec->size() . "\n";

这会打印“42”,正如它应该的那样。

然后我尝试测试使用 IPC::Shareable 的方法。我编写了两个 Perl 脚本,一个“服务器”和一个“客户端”,来测试资源共享。

“服务器”:

use IPC::Shareable;
use example;

# v_ for variable, g_ for (IPC) glue

my $v_array;
my $v_rect;

my %options = ( create => 'yes', exclusive => 0, mode => 0644, destroy => 'yes' );

tie $v_array, 'IPC::Shareable', 'g_array', { %options } or die;
tie $v_rect,  'IPC::Shareable', 'g_rect',  { %options } or die;

$v_array = [ "0" ];

$v_rect = new example::Rectangle;
$v_rect->set( 6, 7 );

while ( 1 ) {
    print "server array: " . join( " - ", @$v_array ) . "\n";
    print "server rect:  " . $v_rect->size() . "\n";
    sleep 3;
}

“客户端”:

use IPC::Shareable;
use example;

# v_ for variable, g_ for (IPC) glue

my $v_array;
my $v_rect;

my %options = ( create => 0, exclusive => 0, mode => 0644, destroy => 0 );

tie $v_array, 'IPC::Shareable', 'g_array', { %options } or die;
tie $v_rect,  'IPC::Shareable', 'g_rect',  { %options } or die;

my $count = 0;

while ( 1 ) {
    print "client array: " . join( " - ", @$v_array ) . "\n";
    print "client rect:  " . $v_rect->size() . "\n";
    push( @$v_array, ++$count );
    $v_rect->set( 3, $count );
    sleep 3;
}

首先启动“服务器”,然后是“客户端”,我得到“服务器”的输出:

server array: 0
server rect:  42
server array: 0 - 1
server rect:  42
server array: 0 - 1 - 2
server rect:  42

“客户端”的输出:

client array: 0
client rect:  0
client array: 0 - 1
client rect:  3
client array: 0 - 1 - 2
client rect:  6

显然,数组引用被共享好吧,但是客户端没有“看到”服务器的 example::Rectangle,而是在一块(零初始化的)流氓内存上工作,而服务器对此一无所知......

我怀疑我必须做点什么$v_rect 使其正常工作,但我对 OO Perl 的了解不够扎实,不知道是什么。有人来救援吗?

For a certain Perl project of mine I need several Perl processes to share some resources, located in a C++ library. (Don't ask, it's not the core of this question, just the context.)

Thus I am trying to delve my way into two "new" fields in this context: IPC::Shareable, and wrapping C++ using SWIG. It seems I am doing something wrong there, and that is what I would like to ask about.


On the C++ side, I wrote a small test class Rectangle with an empty constructor, a set and a size member function.

Then I wrapped the class in a SWIG-generated Perl package example.

On the Perl side, I tried if the SWIG module works as expected:

use example;
my $testrec = new example::Rectangle;
$testrec->set( 6, 7 );
print $testrec->size() . "\n";

This prints "42", as it should.

Then I tried to test my way into using IPC::Shareable. I wrote two Perl scripts, one "server" and one "client", to test the resource sharing.

The "server":

use IPC::Shareable;
use example;

# v_ for variable, g_ for (IPC) glue

my $v_array;
my $v_rect;

my %options = ( create => 'yes', exclusive => 0, mode => 0644, destroy => 'yes' );

tie $v_array, 'IPC::Shareable', 'g_array', { %options } or die;
tie $v_rect,  'IPC::Shareable', 'g_rect',  { %options } or die;

$v_array = [ "0" ];

$v_rect = new example::Rectangle;
$v_rect->set( 6, 7 );

while ( 1 ) {
    print "server array: " . join( " - ", @$v_array ) . "\n";
    print "server rect:  " . $v_rect->size() . "\n";
    sleep 3;
}

The "client":

use IPC::Shareable;
use example;

# v_ for variable, g_ for (IPC) glue

my $v_array;
my $v_rect;

my %options = ( create => 0, exclusive => 0, mode => 0644, destroy => 0 );

tie $v_array, 'IPC::Shareable', 'g_array', { %options } or die;
tie $v_rect,  'IPC::Shareable', 'g_rect',  { %options } or die;

my $count = 0;

while ( 1 ) {
    print "client array: " . join( " - ", @$v_array ) . "\n";
    print "client rect:  " . $v_rect->size() . "\n";
    push( @$v_array, ++$count );
    $v_rect->set( 3, $count );
    sleep 3;
}

Starting first the "server", then the "client", I get this output for the "server":

server array: 0
server rect:  42
server array: 0 - 1
server rect:  42
server array: 0 - 1 - 2
server rect:  42

And this output for the "client":

client array: 0
client rect:  0
client array: 0 - 1
client rect:  3
client array: 0 - 1 - 2
client rect:  6

So apparently, the array reference gets shared allright, but the client doesn't "see" the example::Rectangle of the server, but works on a (zero-initialized) piece of rogue memory, which in turn the server knows nothing about...

I have a suspicion that I have to do something to $v_rect to make this work properly, but I am not solid enough in OO Perl to know what. Anyone to the rescue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜未央樱花落 2024-12-13 06:41:01

你想做的事是行不通的。您将不得不硬着头皮进行某种形式的消息传递。

我不太记得 SWIG 是如何准确地包装 Perl 的 C(++) 级对象,但它很可能是常见的、不可否认的可怕的“整数槽中的指针”策略。在此设置中,它将分配一个 C(++) 对象并将指向它的指针存储在 Perl 标量中。 Perl 对象将是对此标量的祝福引用。当对 Perl 对象的所有引用都消失时,C(++) 对象将由 Perl 类的析构函数显式释放。更现代的技术类似于 XS::Object::Magic 模块允许您执行的操作。

但包装的细节并不那么重要。重要的是该对象对于 Perl 是不透明的!就关系而言,IPC::Shareable 无论如何都使用了一些过时且坦率地说脆弱的技术。它可能适用于您的 Perl 对象,也可能不适用于您的 Perl 对象。但是当您共享 Perl 对象时,C(++) 对象将不会被共享。怎么可能呢? Perl对此一无所知。而且这不可能。

相反,您应该做的是考虑消息传递和序列化方面的问题。为了序列化您的 C(++) 对象,您需要允许 C 方面的一些合作。看一下 Storable 模块提供的用于序列化对象的钩子。就消息传递/队列而言,我很喜欢使用 ZeroMQ,它为您提供了一个简单的类似套接字的接口。

What you are trying to do will not work. You will have to bite the bullet and do some form of message passing instead.

I don't quite remember how exactly SWIG wraps the C(++)-level objects for Perl, but it's most likely the usual, admittedly horrible "pointer in integer slot" strategy. In this setup, it will allocate a C(++) object and store a pointer to it in a Perl scalar. The Perl object will be a blessed reference to this scalar. The C(++) object will be freed explicitly by the destructor of the Perl class when all references to the Perl object have gone away. A more modern technique for this would be something like what the XS::Object::Magic module allows you to do.

But the details of the wrapper aren't even that important. What matters is that the object is opaque to Perl! With ties, IPC::Shareable uses somewhat out-of-fashion and frankly fragile technology anyway. It may or may not work well for your Perl objects. But when you share the Perl object, the C(++) object will NOT be shared. How could it? Perl knows nothing about it. And it can't possibly.

What you should do instead is think about the problem in terms of message passing and serialization. In order to serialize your C(++) objects, you'll want to allow for some cooperation from the C side of things. Have a look at the hooks that the Storable module provides for serializing objects. As far as message passing/queuing goes, I have enjoyed working with ZeroMQ, which gives you a simple socket-like interface.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文