I wrote a simplistic HTTP server in Perl.
To serve some requests, an external program is being executed to provide the desired output.
Obviously to execute an external program fork()
(and exec
) is being used at the kernel level, even when I just use open(my $fh, "-|")
in Perl.
The server runs fine, but it cannot serve two concurrent clients, mostly because the main loop looks like this (I would need some state information per client, too):
#...
{
my (%daemon_options, $daemon);
#...
$daemon = HTTP::Daemon->new(%daemon_options) ||
die "failed to create HTTP::Daemon\n";
while (defined(my $conn = $daemon->accept)) {
#...
while (defined(my $req = $conn->get_request)) {
my $resp;
# check and handle request
$conn->send_response($resp);
}
$conn->close or print "close failed: $!\n";
undef($conn);
}
#...
}
#...
So I wanted to create a thread for each client connection, allowing to handle the client requests concurrently.
However perlthrtut
warns:
Thinking of mixing "fork()" and threads? Please lie down and wait until the feeling passes.
So I'm wondering whether to use forking to create processes handling client requests, or to use threads handling client requests. As I'd also like to collect some statistics in the main thread, I'd prefer using threads (and shared some variables).
How safe is mixing forking and multi-threading in this context? As I understand it it will do "forking in threads", but not "create new threads in a forked process"; however any fork would duplicate any existing thread, right?
I'm using (rather old) Perl 5.18 on x86_64 running Linux.
threads
in Perl are originally the way howfork
was emulated on MSWin. Don't mix the two models. Use IPC with forks to share data, or usethreads
for everything, ideally with something like Thread::Queue.STDOUT
to a variable, likeopen my $fh_stdout, '>', \my $stdout;
andmy $fh_STDOUT = select $fh_stdout;
and then all writes wind up in it. Eventually send that over to the parent. (Can also serialize any other data that should be sent over, and JSON is fine for that for example.) UseIO::Select
in the parent to sort all that from various forks