4

The code below works fine on mod_cgi but not on mod_perl. The code just crashes upon creation of the first thread. Any thoughts on how to implement threads on mod_perl? Is it really possible? What am I missing?

use strict;
use warnings;
use threads;

print "Content-type: text/html\n\n";

sub testthread{
   my $value = shift;
   print "<br>test - $value"
}

my @threads = ();
push(@threads, threads->new(\&testthread, 1));
push(@threads, threads->new(\&testthread, 2));
foreach (@threads) {
   $_->join;
}

exit;

There is no error message given. My web page / script just stops and gives this error to the browser: The www.abcd.com page isn’t working www.abcd.com didn’t send any data. What's weird is if I execute the script via command line it works fine.

john
  • 93
  • 9
  • 1
    What are you trying to accomplish? I'd suggest trying to mutlithread CGI script type stuff is asking for some real pain, to the point where you'd probably be better off looking at running a web framework instead (mojolicious/dancer or similar) – Sobrique Jul 27 '16 at 09:19
  • I already have a cgi script that uses multi threading then would like to utilize mod_perl to make it more faster and efficient. But I cannot get threads to work on mod_perl. – john Jul 27 '16 at 09:32
  • You don't even need a framework, but using Plack (plain or with a framework) makes your live incredibly more easy. There are PSGI servers that bring automatic forking, pre-forking and there might be one that does threading if you actually want that. You can tie all of them into your web server so it feels like it's mod_perl. – simbabque Jul 27 '16 at 09:32
  • Hmmm so threads really does not work with mod_perl? – john Jul 27 '16 at 09:38

2 Answers2

2

so threads really do not work with mod_perl?

I have not investigated whether threads work or do not work with mod_perl2. Keep in mind that the point of mod_perl is to run a set of persistent Perl interpreters within the Apache process.

Also keep in mind that Apache can kill CGI scripts that are taking too long to respond. Now, add to that mix a set of threads which your CGI script that can die at any time is managing within some persistent Perl process within Apache, and I hope it is easy to see why people's first reaction is "Great idea!" This would never occur to me as a solution to any problem I have encountered in CGI programming.

What you may or may not be able to do may depend greatly on the MPM you choose and how httpd and perl you are using were compiled etc.

You need to explain why you think you need threads. What is the problem you are trying to solve, and how will using threads within a CGI script run under mod_perl will help you solve it?

See mod_perl documentation:

Threads Support

In order to adapt to the Apache 2.0 threads architecture (for threaded MPMs), mod_perl 2.0 needs to use thread-safe Perl interpreters, also known as "ithreads" (Interpreter Threads). This mechanism can be enabled at compile time and ensures that each Perl interpreter uses its private PerlInterpreter structure for storing its symbol tables, stacks and other Perl runtime mechanisms. When this separation is engaged any number of threads in the same process can safely perform concurrent callbacks into Perl. This of course requires each thread to have its own PerlInterpreter object, or at least that each instance is only accessed by one thread at any given time.

The first mod_perl generation has only a single PerlInterpreter, which is constructed by the parent process, then inherited across the forks to child processes. mod_perl 2.0 has a configurable number of PerlInterpreters and two classes of interpreters, parent and clone. A parent is like that in mod_perl 1.0, where the main interpreter created at startup time compiles any pre-loaded Perl code. A clone is created from the parent using the Perl API perl_clone() function. At request time, parent interpreters are only used for making more clones, as the clones are the interpreters which actually handle requests. Care is taken by Perl to copy only mutable data, which means that no runtime locking is required and read-only data such as the syntax tree is shared from the parent, which should reduce the overall mod_perl memory footprint.

Rather than create a PerlInterpreter per-thread by default, mod_perl creates a pool of interpreters. The pool mechanism helps cut down memory usage a great deal. As already mentioned, the syntax tree is shared between all cloned interpreters. If your server is serving more than mod_perl requests, having a smaller number of PerlInterpreters than the number of threads will clearly cut down on memory usage. Finally and perhaps the biggest win is memory re-use: as calls are made into Perl subroutines, memory allocations are made for variables when they are used for the first time. Subsequent use of variables may allocate more memory, e.g. if a scalar variable needs to hold a longer string than it did before, or an array has new elements added. As an optimization, Perl hangs onto these allocations, even though their values "go out of scope". mod_perl 2.0 has a much better control over which PerlInterpreters are used for incoming requests. The interpreters are stored in two linked lists, one for available interpreters and another for busy ones. When needed to handle a request, one interpreter is taken from the head of the available list and put back into the head of the same list when done. This means if for example you have 10 interpreters configured to be cloned at startup time, but no more than 5 are ever used concurrently, those 5 continue to reuse Perl's allocations, while the other 5 remain much smaller, but ready to go if the need arises.

Various attributes of the pools are configurable using threads mode specific directives.

The interpreters pool mechanism has been abstracted into an API known as "tipool", Thread Item Pool. This pool can be used to manage any data structure, in which you wish to have a smaller number than the number of configured threads. For example a replacement for Apache::DBI based on the tipool will allow to reuse database connections between multiple threads of the same process.

Thread-environment Issues

While mod_perl itself is thread-safe, you may have issues with the thread-safety of your code. For more information refer to Threads Coding Issues Under mod_perl.

Another issue is that "global" variables are only global to the interpreter in which they are created. It's possible to share variables between several threads running in the same process. For more information see: Shared Variables.

Community
  • 1
  • 1
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
  • I needed threads to execute numerous mysql queries simultaneously so that the waiting time does not add up. – john Jul 28 '16 at 21:13
  • A problem I would worry about is what happens to your database server if, say, 100 users come to your web site (they might hit it at a rate of 1/second), you spawn 10 simultaneous queries for each, and cause the database server to trash. I don't know if the results of these queries are cacheable, but, you might have an easier time using a framework such as Mojolicious. Possibly fewer complications. Although, I would recommend trying this out, and asking when you run into specific problems. – Sinan Ünür Jul 28 '16 at 22:02
  • I already have a working code that runs smoothly on mod_cgi. The problem is when running on mod_perl it crashes, specifically on the "threads->new" line. Is there a setting that should be enabled to make threads work on mod_perl? Or am I missing something? – john Jul 29 '16 at 06:46
  • "crashes" is not an adequate problem description. Tell us what error you get, what do you get from `perl -V` etc etc. Update your question with that information. – Sinan Ünür Jul 29 '16 at 09:25
  • There is no error message. My web page / script just stops and gives the error: The www.abcd.com page isn’t working www.abcd.com didn’t send any data. What's weird is if I execute the script via command line it works fine. – john Jul 29 '16 at 09:38
  • If you do not know where to look for any error messages, you are likely not well equipped to deal with this problem. – Sinan Ünür Jul 29 '16 at 10:00
0

We run mod_perl with the Apache event Multi-Processing Module (MPM) and APACHE::DBI with MySQL 5.7 to handle high surges of users logging in and starting quizzes/exams.

We have Apache 2.4 configured to start with 50 children and each child runs 100 threads for a total of 5,000 threads available for requests. Because mod_perl also runs multi threaded and is bundled into Apache (upon startup), memory consumption is minimal when compared to other languages.

We set Apache to always have 3,500 threads available and to max out at 200 children (20,000 threads). Children recycle after handling 10,000 requests (in case of any memory leakage). When Apache recycles its logs every night, Apache gets restarted along with mod_perl and all database connections and starts with the 5,000 threads available again.

With mod_perl we start with 50 children to match the apache children and it also recycles it's children.

In Virtual Server directive we have:

PerlInterpStart 50 PerlInterpMaxSpares 50 PerlInterpMax 100

Real simplicity for very high scalability and stability and low cost hardware. And it runs well on windows too. If your stuff doesn't run multi threaded it's limited to each request requiring a child (a 1:1 ratio) instead of a thread (a 1:100 ratio). Each child requires an instance of your program to run (other than Java?) so memory consumption is very high versus using mod_perl. We know people say it's old, but it runs so well and stable and is supported on probably more operating systems than any other language and it just works.

ivan
  • 1
  • 1