in reply to problem porting to threaded mode

The most obvious question is why you want to shift to Apache2 threaded MPM and perl ithreads. It seems like a source of trouble to me with no obvious benefits.

Anyways you are trying to do it, so what is going wrong in your attempts? Well the first problem was that {} can't be shared. You can wrap it with shared or shared_clone to solve that problem, and you did. But then you have a situation where you have declared a shared variable and then try to tie it. But as Liz says in Things you need to know before programming Perl ithreads, sharing already works through a tie so you can't tie a shared variable. So your dbs continue to look like empty hashes after the tie. Then you got rid of the share and ran into the fact that DB_File is a C-level library that was never designed to be thread safe..

How then can you solve this? Your best bet i Thread::Shared. From the documentation you should not share the variables and instead write something like this:

tie %{$dbs[$db]}, "Thread::Shared", {module => "DB_File"}, $dbfn[$db], + O_RDONLY or die ((caller 0)[3]. " can't tie " . $dbfn[$db] . ": $!");
Alternately in the unshared version you can try to replace DB_File with something else. BerkeleyDB is a more sophisticated version of the same, but I doubt it is thread-safe. The pure Perl DBM::Deep is more promising. It should be easy to do a one-time copy from one format to the other. I'd be somewhat concerned about whether seeks on the database file in different threads could interfere with each other, but you can test that fairly easily and it probably works. (I'm paranoid though, and would test it.)

Update: Also don't forget to use locking where appropriate!

Replies are listed 'Best First'.
Re^2: problem porting to threaded mode
by Anonymous Monk on Jan 01, 2009 at 19:33 UTC
    Why? Mostly so I can use a lower-cost hosting plan from my IHP, whose plans include a maximum number of processes. When I get it working I mean to run some performance tests between the 'event' version and the 'prefork' version, and decide which to stay with.

    Are you sure you mean to say "Thread::Shared"? Its documentation on CPAN includes nothing like the "tie" usage that you recommend. The article by Liz mentions a "proof of concept" module that she wrote called "Thread::Tie" that has such use noted, including {method => ...} as the 3rd operand. But then the Thread::Tie doc says that it should be superceded by an XS/C version for production use.

    I'm pretty sure that @dbs has to be shared by some method, so that any thread can untie and retie a hash/db when the db changes, and have this action be effective for all of the threads in the process. I only backed away from having it shared as an experiment/data point.

    An alternative that just occurred to me is to create one thread that does all of the DB accesses for the other threads. No sharing needed! Your thoughts (or anyone else's) on this approach? Can I create the thread at post-config time and have it carried over into all the Apache child processes?

    If anything, my mod_perl2 code probably contains more locks than necessary at this point. I have gotten several answers from module authors that their modules are thread-safe (or "can't see any reason why not") and have taken locks out accordingly.

    Thanks and HNY, cmac