2

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.

4
  • 1
    What the documentation tells you is good advice. threads in Perl are originally the way how fork was emulated on MSWin. Don't mix the two models. Use IPC with forks to share data, or use threads for everything, ideally with something like Thread::Queue.
    – choroba
    Commented Oct 6, 2023 at 11:46
  • I had mixed processes and threads in C in the past, but there (in C) you have more control over what's actually going on. As I wrote some forking stuff using shared memory to exchange information in Perl in the past, too, I'll do it again, ignoring the existence of thread in Perl (unless someone convinces me to try something else).
    – U. Windl
    Commented Oct 6, 2023 at 12:19
  • Well, one can thread any process, so inside a fork-ed process as well. It's just .. . why? It's asking for trouble. I also like the doc's advice. (Cannot fork inside a thread at all though, I think, as that would mix things up too much) So you use one model I'd say. Then, threads being large and slow in Perl, I don't see them as a good tool for this; so I'd fork for each new request.
    – zdim
    Commented Oct 6, 2023 at 19:09
  • Then one way for assembling various output from forks is that in each fork redirect STDOUT to a variable, like open my $fh_stdout, '>', \my $stdout; and my $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.) Use IO::Select in the parent to sort all that from various forks
    – zdim
    Commented Oct 6, 2023 at 19:11

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.