2013-06-22 1 views
0

Я использовал эту статью: http://www.perlmonks.org/?node_id=594175 написать код, объединив DBI с вилкой. Он работает в Linux, но не работает в Windows XP. Я использую Active State Perl v5.10.0 MSWin32-x86-multi-thread, DBD :: mysql v4.011.DBI и fork не работают на Windows

В Linux Perl v5.16.1 i486-linux-thread-multi DBD :: mysql v4.021.

Код. dbi_fork.pl:

#!/usr/bin/perl 

use strict; 
use warnings; 
use DBI; 
require "mysql.pl"; 

my $dbh = connect_mysql(); 

if (fork()) { 
    $dbh->do("UPDATE articles SET title='parent' WHERE id=1"); 
} 
else { 
    my $dbh_child = $dbh->clone(); 
    $dbh->{InactiveDestroy} = 1; 
    undef $dbh; 
    $dbh_child->do("UPDATE articles SET title='child' WHERE id=2"); 
} 

mysql.pl:

sub connect_mysql 
{ 
    my $user_db = 'user'; 
    my $password_db = 'secret'; 
    my $base_name = 'test'; 
    my $mysql_host_url = 'localhost'; 

    my $dsn = "DBI:mysql:$base_name:$mysql_host_url"; 
    my $dbh = DBI->connect($dsn, $user_db, $password_db) or die $DBI::errstr; 

    return $dbh; 
} 

1; 

статьи таблица:

DROP TABLE IF EXISTS `articles`; 
CREATE TABLE `articles` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `title` varchar(50) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 

-- ---------------------------- 
-- Records of articles 
-- ---------------------------- 
INSERT INTO `articles` VALUES ('1', 'title1'); 
INSERT INTO `articles` VALUES ('2', 'title2'); 

В Windows он выдает ошибку:

$ perl ./dbi_fork.pl 
DBD::mysql::db clone failed: handle 2 is owned by thread 2344b4 not current 
thread 1a45014 (handles can't be shared between threads and your driver may 
need a CLONE method added) at ./dbi_fork.pl line 14. 

Как исправить?

+3

** (1) ** Вы не можете сравнить поведение из Версия для Windows с версией Linux; здесь слишком много переменных. Вы можете уменьшить количество переменных, установив perl5.16 в поле XP (например, [Strawberry Perl] (http://strawberryperl.com/)) и установив ту же версию DBD :: mysql. ** (2) ** В любом случае Windows не имеет встроенной 'fork'. Вместо этого он эмулируется с помощью потоков. Похоже, что проблему можно обойти, клонируя дескриптор перед «вилкой» и с каждой стороны закройте неиспользованный дескриптор. Или ребенок запускает 'connect_mysql' заново для получения второго дескриптора. – amon

+0

@amon: Вы должны опубликовать это как ответ. – Borodin

ответ

4

В Windows нет такой вещи, как fork. Это особенность, характерная для систем unix. Perl эмулирует его, используя потоки в Windows, и это вызывает проблемы.

Вместо того чтобы пытаться воссоздать существующее соединение, просто создайте соединения в задаче.

Другими словами, используйте

if (fork()) { 
    my $dbh = connect_mysql(); 
    $dbh->do(...); 
} else { 
    my $dbh = connect_mysql(); 
    $dbh->do(...); 
} 
+0

Я не заметил, что вы использовали странный взломать, чтобы попытаться создать новое соединение в дочернем процессе. Думаю, я прекратил платить attn после того, как заметил, что вы только подключены один раз, так что мое объяснение было немного выключено, но решение по-прежнему применяется. Обновленное объяснение. – ikegami

2

Вот решение - каждый поток создает свою собственную связь:

#!/usr/bin/perl 

use strict; 
use warnings; 
use DBI; 
require "mysql.pl"; 

if (fork()) { 
    my $dbh = connect_mysql(); 
    $dbh->do("UPDATE articles SET title='parent' WHERE id=1"); 
} 
else { 
    my $dbh = connect_mysql(); 
    $dbh->do("UPDATE articles SET title='child' WHERE id=2"); 
} 
+1

Это лучший подход. –