FloydATC has asked for the wisdom of the Perl Monks concerning the following question:

I have a script running fine under Linux, this is how it works:
use DBI; while (1) { my $dbh = DBI->connect(); # Parent connecting # .. get a job list .. $dbh->disconnect(); # <-- NB! foreach my $job (@jobs) { my $pid = fork(); if (defined $pid) { if ($pid) { $children{$pid} = time; # This is the parent } else { child($job); # This is the child process } } else { logmsg "fork() failed: $!\n"; } } sleep 1; } sub child { my $job = shift; my $dbh = DBI->connect(); # Child connecting # .. do the job .. $dbh->disconnect(); exit; }
I thought I had avoided the potential problems involved with sharing a handle between processes, but much to my surprise ActivePerl on WinXP crashes when the child tries to connect:

DBD::mysql::dr connect failed: handle 1 is owned by thread 183f3e8 not + current thread 260eb64 (handles can't be shared between threads and +your driver may need a CLONE method added) at C:/PERL/site/lib/DBI.pm + line 598. DBD::mysql::dr disconnect_all failed: handle 1 is owned by thread 183f +3e8 not current thread 260eb64 (handles can't be shared between threa +ds and your driver may need a CLONE method added) at C:/PERL/site/lib +/DBI.pm line 677. END failed--call queue aborted.
What handle am I trying to share? Why is the parent $dbh not destroyed before the child process tries to connect?

Replies are listed 'Best First'.
Re: DBI and fork() on Win32
by Corion (Patriarch) on Feb 10, 2009 at 13:55 UTC

    What you're doing is dangerous already on Linux/Unix. Not all DBDs support fork() on Unix. You take care to disconnect, which might prevent most of the problems. On Windows, fork() is only emulated through threads, and thus, all of the caveats in the DBI documentation about threads apply there. You should have one (and only one) DBI connection in your process. If you want to do parallel processing using a database (which I doubt will be efficient), then I recommend you launch separate child processes through system(1, ...) or system("start $cmd") to have really separate DBI handles.

      Thanks, I think I understand, it's not the handle but the driver that causes problems?

      Unfortunately, system() doesn't help because I need each job to be executed in paralell and I don't want to sit around and wait for each one of them.

      I have tried rewriting &child() like this:

      sub child { my $job = shift; exec("perl", "child-script", $job); exit; # Just in case }
      ...but DBI still crashes with the same message.

        exec is not the solution. I didn't show a plain system() call but system(1, ...), which is mentioned in perlport, and which executes the program separately from the main program. This is mostly the same as system("start $cmd"); except that the latter involves the shell.

Re: DBI and fork() on Win32
by Anonymous Monk on Feb 10, 2009 at 15:59 UTC
    Hello,

    Just throwing in my 1c, but you could always use POE and one of it's DBI components which have been tested and is known to work on windows. However, POE might not be a good fit for your application :(

    POE::Component::EasyDBI, POE::Component::SimpleDBI is the two I know that boasts of MSWin32 compatibility. Others might be lurking on CPAN :)

    Otherwise, hope you successfully navigate the intricacies of fork() and MSWin32's crappy emulation of it!
Re: DBI and fork() on Win32
by Illuminatus (Curate) on Feb 10, 2009 at 14:54 UTC
    Is there really a difference between fork() and system() on Windows? System is implemented in most places as a fork, then as exec, with the parent simply waiting for the child to exit. There should be no difference. One thing the DBI page suggests:
    $rc = $dbh->disconnect or warn $dbh->errstr;
    which might shed some light. Also, unless your code is incomplete, I don't see 'use strict' or 'use warnings'. It also might be helpful to identify the database you are using.
      Is there really a difference between fork() and system() on Windows? System is implemented in most places as a fork, then as exec, with the parent simply waiting for the child to exit. There should be no difference.

      Yes. They are completely different on Win32. There is no OS provided fork on win32, so system cannot be implemented using "fork & exec".


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      Is there really a difference between fork() and system() on Windows?

      Windows has neither a fork system call nor an exec system call. Necessarily, yes, they are different.

      Perl emulates fork using threads, whereas system results in a call to CreateProcess.

      [ Oops, I opened the parent a while before I replied and forgot to check if it was already answered. ]