user4035
user4035

Reputation: 23729

DBI and fork don't work on Windows

I used this article: http://www.perlmonks.org/?node_id=594175 to write code, combining DBI with fork. It works on Linux, but doesn't work on Windows XP. I am using Active state Perl v5.10.0 MSWin32-x86-multi-thread, DBD::mysql v4.011.

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

Code. 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;

articles table:

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');

On Windows it gives an error:

$ 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.

How to fix?

Upvotes: 0

Views: 890

Answers (2)

ikegami
ikegami

Reputation: 385764

There's no such thing as fork on Windows. It's a feature specific to unix systems. Perl emulates it using threads on Windows, and this is causing problems.

Rather than trying to recreate an existing connection, simply create the connections in the task.

In other words, use

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

Upvotes: 4

user4035
user4035

Reputation: 23729

Here is the solution - every thread creates it's own connection:

#!/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");
}

Upvotes: 2

Related Questions