Perl: IPC :: Shareable и SWIG-объект C ++ не согласны - PullRequest
5 голосов
/ 22 сентября 2011

Для определенного моего проекта Perl мне нужно несколько процессов Perl, чтобы разделить некоторые ресурсы, расположенные в библиотеке C ++. (Не спрашивайте, это не суть этого вопроса, а только контекст.)

Таким образом, я пытаюсь углубиться в два «новых» поля в этом контексте: IPC::Shareable и обертывание C ++ с помощью SWIG. Кажется, я делаю что-то не так, и это то, о чем я хотел бы спросить.


На стороне 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

Так что, очевидно, ссылка на массив распределяется нормально, но клиент не «видит» пример :: Rectangle сервера, но работает с (инициализируемым нулями) фрагментом мошеннической памяти, которая, в свою очередь, является сервером ничего не знает о ...

У меня есть подозрение, что я должен сделать что-то для $v_rect, чтобы заставить это работать должным образом, но я не достаточно тверд в OO Perl, чтобы знать, что. Кто-нибудь на помощь?

1 Ответ

3 голосов
/ 22 сентября 2011

То, что вы пытаетесь сделать, не сработает. Вам придется прикусить пулю и вместо этого сделать какую-то форму передачи сообщений.

Я не совсем помню, как именно SWIG оборачивает объекты уровня C (++) для Perl, но это, скорее всего, обычная, по общему признанию, ужасная стратегия "указатель в целочисленном слоте". В этой настройке он выделит объект C (++) и сохранит указатель на него в скаляре Perl. Объект Perl будет благословенной ссылкой на этот скаляр. Объект C (++) будет явно освобожден деструктором класса Perl, когда все ссылки на объект Perl исчезнут. Более современный метод для этого был бы чем-то вроде того, что позволяет делать модуль XS :: Object :: Magic.

Но детали обертки даже не так важны. Важно то, что объект непрозрачен для Perl! В связи со связями IPC :: Shareable использует несколько устаревшие и откровенно хрупкие технологии в любом случае. Это может или не может работать хорошо для ваших объектов Perl. Но когда вы разделяете объект Perl, объект C (++) будет NOT . Как это могло? Perl ничего не знает об этом. И это не может быть возможно.

Вместо этого вам следует подумать о проблеме с точки зрения передачи сообщений и сериализации. Чтобы сериализовать ваши объекты C (++), вы должны разрешить некоторое сотрудничество со стороны C. Посмотрите на хуки, которые предоставляет модуль Storable для сериализации объектов. Что касается передачи сообщений / очередей, мне очень понравилось работать с ZeroMQ, который предоставляет вам простой интерфейс в виде сокетов.

...