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(开发者_如何学C) . "\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?
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.
精彩评论