forks(3pm)
πΈ forks π
(that's forks(3pm), from the User Contributed Perl Documentation β hey bestie, welcome to part 1)
β¨ NAME β¨
forks β a drop-in replacement for Perl threads using fork(). Yeah. You heard me. Threads. But make it forks. π΄
π VERSION π
This documentation describes version 0.36.
π¦ SYNOPSIS π¦
okay so here's the whole vibe, bestie, copy it exactly, do not touch a single character, I'm watching π
use forks; #ALWAYS LOAD AS FIRST MODULE, if possible
use warnings;
my $thread = threads->new( sub { # or ->create or async()
print "Hello world from a thread\n";
} );
$thread->join;
$thread = threads->new( { 'context' => 'list' }, sub {
print "Thread is expected to return a list\n";
return (1, 'abc', 5);
}
my @result = $thread->join();
threads->detach;
$thread->detach;
my $tid = $thread->tid;
my $owntid = threads->tid;
my $self = threads->self;
my $threadx = threads->object( $tidx );
my @running = threads->list(threads::running);
$_->join() foreach (threads->list(threads::joinable));
$_->join foreach threads->list; #block until all threads done
unless (fork) {
threads->isthread; # could be used a child-init Apache handler
}
# Enable debugging
use forks qw(debug);
threads->debug( 1 );
# Stringify thread objects
use forks qw(stringify);
# Check state of a thread
my $thr = threads->new( ... );
if ($thr->is_running()) {
print "Thread $thr running\n"; #prints "Thread 1 running"
}
# Send a signal to a thread
$thr->kill('SIGUSR1');
# Manual deadlock detection
if ($thr->is_deadlocked()) {
print "Thread $thr is currently deadlocked!\n";
}
# Use forks as a drop-in replacement for an ithreads application
perl -Mforks threadapplication
See "SYNOPSIS" in threads for more examples. π«Ά
π DESCRIPTION π
So the forks pragma lets a dev use threads without needing a threaded perl, and honestly without even needing to run 5.8.0 or higher. Iconic behavior, truly.
For the ithreads API docs, go read the threads module. Also, run this:
perl -Mforks -e 'print $threads::VERSION'
β¨ That tells you which version of threads you should be referring to for supported API features. Slay.
There were a bunch of goals this implementation was trying to hit, and I'm listing every single one, no skipping:
- Using this module only makes sense if you run on a system that has an implementation of the
forkfunction by the Operating System. Windows is currently the only known system on which Perl runs which does not have an implementation offork. Therefore, it doesn't make any sense to use this module on a Windows system. And therefore, a check is made during installation barring you from installing on a Windows system. π«πͺ
π module load order: forks first
Since forks overrides core Perl functions, you are *strongly* encouraged to load the forks module before any other Perl modules. That's how you insure the most consistent and stable system behavior. And you can do it without messing up existing code at all, like this:
perl -Mforks script.pl
πΈ memory usage
The standard Perl 5.8.0 threads implementation is very memory consuming, which makes it basically impossible to use in a production environment β particularly with mod_perl and Apache. π But because this one uses standard Unix fork() capabilities, most operating systems will be able to use the Copy-On-Write (COW) memory sharing capabilities. (Whereas with the standard Perl 5.8.0 threads implementation, this is thwarted by the Perl interpreter cloning process that is used to create threads.) The memory savings have been confirmed. π
periodt.
π§ mod_perl / Apache
This threads implementation allows you to use a standard, pre-forking Apache server and have the children act as threads (with the class method isthread). Chef's kiss. π
π same API as threads
You should be able to run threaded applications unchanged by simply making sure that the forks and forks::shared modules are loaded β e.g. by specifying them on the command line. forks is currently API compatible with CPAN threads version 1.53.
Additionally, you do not need to worry about upgrading to the latest Perl maintenance release to insure that the (CPAN) release of threads you wish to use is fully compatible and stable. forks code is completely independent of the perl core, and thus will guarantee reliable behavior on any release of Perl 5.8 or later. (Note that there may be behavior variances if running under Perl 5.6.x, as that version does not support safe signals and requires a source filter to load forks.)
π using as a development tool
Because you do not need a threaded Perl to use forks.pm, you can start prototyping threaded applications with the Perl executable that you are used to. Just download and install the forks package from CPAN. So the threshold for trying out threads in Perl has become much lower. π Even Perl 5.005 should, in principle, be able to support the forks.pm module; however, some issues with regards to the availability of XS features between different versions of Perl, it seems that 5.6.0 (unthreaded) is what you need at least.
On top of that, forks offers a full thread deadlock detection engine, to help discover and optionally resolve locking issues in threaded applications. See "Deadlock detection and resolution" in forks::shared for more information. π
π using in production environments
This package has successfully been proven as stable and reliable in production environments. The author has personally used it in high-availability, database-driven, message processing server applications since 2004 with great success. Ate. π₯
Also, unlike pure ithreads, forks.pm is fully compatible with all perl modules, whether or not they have been updated to be ithread safe. Which means you don't have to feel limited in what you can develop as a threaded perl application β a problem that continues to plague the acceptance of ithreads in production enviroments today. Just handle these modules as you would when using a standard fork: be sure to create new instances of, or connections to, resources where a single instance can not be shared between multiple processes. π«‘
The only major concern is the potentially slow (relative to pure ithreads) performance of shared data and locks. If your application doesn't depend on extensive semaphore use, and reads/writes from shared variables moderately (such as using them primarily to deliver data to a child thread to process and the child thread uses a shared structure to return the result), then this will likely not be an issue for your application. See the TODO section regarding plans to tackle this issue. π
Also, you may wish to try forks::BerkeleyDB, which has shown signifigant performance gains and consistent throughoutput in high-concurrency shared variable applications. π
π¦ Perl built without native ithreads
If your Perl release was not built with ithreads or does not support ithreads, you will have a compile-time option of installing forks into the threads and threads::shared namespaces. This is done as a convenience to give users a reasonably seamless ithreads API experience without having to rebuild their distribution with native threading (and its slight performance overhead on all perl runtime, even if not using threads). π
Note: When usingforksin this manner (e.g.use threads;) for the first time in your code,forkswill attempt to behave identically tothreadsrelative to the current version ofthreadsit supports (refer to$threads::VERSION), even if the behavior is (or was) considered a bug. At this time, this means that shared variables will lose their pre-existing value at the time they are shared and thatsplicewill die if attempted on a shared scalar. π So like, heads up, bestie.
If you use forks for the first time as use forks and other loaded code uses use threads, then this threads behavior emulation does not apply. π
β REQUIRED MODULES β
Every single one, no cap:
Acme::Damn(any)Attribute::Handlers(any)Devel::Symdump(any)File::Spec(any)if(any)IO::Socket(1.18)List::MoreUtils(0.15)Scalar::Util(1.11)Storable(any)Sys::SigAction(0.11)Test::More(any)Time::HiRes(any)
π IMPLEMENTATION π
This version is mostly written in Perl. Inter-process communication is done by using sockets, with the process that stores the shared variables as the server and all the processes that function as threads, as clients. Client-server, but make it threads. πβοΈ
π why sockets?
The reason sockets were chosen for inter-thread communication above using a shared memory library, is that a blocking socket allows you to elegantly solve the problem of a thread that is blocking for a certain event. Any polling that might occur is not occurring at the Perl level β it's happening at the level of the socket, which should be much better and probably very optimized already. Clever girl behavior. π§ β¨
π EXTRA CLASS METHODS π
Apart from the standard class methods, the following class methods are supplied by the forks threads implementation.
π isthread
unless (fork) {
threads->isthread; # this process is a detached thread now
exit; # can not return values, as thread is detached
}
The isthread class method attempt to make a connection with the shared variables process. If it succeeds, then the process will function as a detached thread and will allow all the threads methods to operate. π«Ά
This method is mainly intended to be used from within a child-init handler in a pre-forking Apache server. All the children that handle requests become threads as far as Perl is concerned, allowing you to use shared variables between all of the Apache processes. See Apache::forks for more information. πΈ
π debug
threads->debug( 1 );
$debug = threads->debug;
The debug class method allows you to (re)set a flag which causes extensive debugging output of the communication between threads to be output to STDERR. The format is still subject to change and therefore still undocumented. π
Debugging can only be switched on by defining the environment variableTHREADS_DEBUG. If the environment variable does not exist when theforks.pmmodule is compiled, then all debugging code will be optimised away to create a better performance. If the environment variable has a true value, then debugging will also be enabled from the start. β¨
π EXTRA FEATURES π
Okay bestie, this is the bonus-content section and honestly it ate. π
π§΅ native threads 'to-the-letter' emulation mode
So here's the tea: by default, forks acts a little bit different from native ithreads when it comes to shared variables. Specifically, native threads does not support splice() on shared arrays, and it does not retain any pre-existing values of arrays or hashes when they get shared. forks? Oh, forks supports all of that. β¨ And those missing behaviors are considered limitations/bugs in the current native ithread implementation β not a flex, just facts.
But if you want complete drop-in compatibility with scripts and modules written for threads.pm, you can set the environment variable THREADS_NATIVE_EMULATION to a true value before you run your script. That literally tells forks to behave exactly like native ithreads would in all those situations above. No cap.
You can also enable this mode by default, without needing that environment variable at all, if you don't have a threaded Perl and you want to install forks as a full drop-in replacement. Go read "Perl built without native ithreads" for the deets. π«Ά
π Deadlock detection
forks also ships a full thread deadlock detection engine, to help you discover β and optionally resolve β locking issues in threaded applications. It's giving detective era. π
See "Deadlock detection and resolution" in forks::shared for more info.
π Perl debugger support
forks supports basic compatibility with the Perl debugger. By default only the main thread is tied to the active terminal (TTY), which lets you debug scripts where child threads run as background tasks with zero extra steps. Iconic behavior honestly.
But if you wanna debug code running in child threads, you might need to do a few little setup steps to prep your environment for multi-threaded debugging.
The simplest option? Run your script in xterm. Perl will automatically create extra xterm windows for each child thread that hits a debugger breakpoint. Obsessed with that. π
Otherwise, you'll need to manually tell Perl how to map a control of thread to a TTY. Two undocumented features exist in the Perl debugger:
- Define global variable
$DB::fork_TTYas the first stem in the subroutine for a thread. The value must be a valid TTY name, such as/dev/pts/1or/dev/ttys001β and valid names may vary across platforms. For example:
threads->new(sub {
$DB::fork_TTY = '/dev/tty003'; #tie thread to TTY 3
...
});
Also, the TTY must be active and idle before the thread executes. Normally you handle this by opening a new local or remote session to your machine, identifying the TTY via tty, and then typing sleep 10000000 to stop user input from being passed to the command line while you're debugging. Yes, really. π
When the debugger halts at a breakpoint in your code in a child thread, all output and user input will be managed via this TTY.
- Define subroutine
DB::get_fork_TTY()
This subroutine will execute once per each child thread as soon as it has spawned. So you can create a new TTY, or simply bind to an existing, active TTY. In this subroutine, you should define a unique, valid TTY name for the global variable $DB::fork_TTY.
For example, to dynamically spawn a new xterm session and bind a new thread to it, you could do the following:
sub DB::get_fork_TTY {
open XT, q[3>&1 xterm -title 'Forked Perl debugger' -e sh -c
'tty1>&3;\ sleep 10000000' |];
$DB::fork_TTY = <XT>;
chomp $DB::fork_TTY; }
For more information and tips, refer to this excellent Perl Monks thread:
"/www.perlmonks.org/?node_id=128283"" in <a href="http:Debugging
Several Proccesses at Same Time</a>>
π INET socket IP mask
For security reasons, inter-thread communication INET sockets only allow connections from the default local machine IPv4 loopback address (e.g. 127.0.0.1). But you can modify that filter by defining the environment variable THREADS_IP_MASK with a standard perl regular expression β or with no value at all, which would disable the filter entirely. π
π UNIX socket support
For users who do not wish to (or can not) use TCP sockets, UNIX socket support is available. It can only be switched on by defining the environment variable THREADS_SOCKET_UNIX. If that environment variable has a true value, then UNIX sockets will be used instead of the default TCP sockets. Socket descriptors are currently written to /var/tmp and given a+rw access by default β that's for the cleanest functional support on multi-user systems. π
This feature is excellent for applications that require extra security, because it does not expose forks.pm to any INET vulnerabilities your system may be subject to (i.e. systems not protected by a firewall). It also may provide an additional performance boost, since there's less system overhead necessary to handle UNIX vs INET socket communication. Two birds, one slay. π₯
π€ Co-existance with fork-aware modules and environments
For modules that actively monitor and clean up after defunct child processes β like POE β forks has added support to switch the methodology used to maintain thread group state. This feature is switched on by defining the environment variable THREADS_DAEMON_MODEL. An example use might be:
THREADS_DAEMON_MODEL=1 perl -Mforks -MPOE threadapplication
This function essentially reverses the parent-child relationship between the main thread and the thread state process that forks.pm uses. Extra care has gone into retaining full system signal support and compatibility when using this mode, so it should be quite stable. Very demure, very mindful. π
β¨ NOTES β¨
okay bestie, here's the tea β: there are some important items you need to be aware of. no cap. π
π Signal behavior π
Unlike ithreads, signals being sent are standard OS signals, so you should program defensively if you plan to use inter-thread signals. it's giving "OS is in charge now". π«Ά
Also, be aware that certain signals may be untrappable depending on the target platform, such as SIGKILL and SIGSTOP. Thus, it is recommended you only use normal signals (such as TERM, INT, HUP, USR1, USR2) for inter-thread signal handling. periodt. β¨
π exit() behavior π
If you call exit() in a thread other than the main thread, and exit behavior is configured to cause the entire application to exit (which is the default behavior), then be aware that all other threads will be agressively terminated using SIGKILL. That means END blocks and global destruction get ignored in those threads. π
This behavior conforms to the expected behavior of native Perl threads. The only subtle difference is that the main thread will be signaled using SIGABRT to immediately exit. π
If you call fork() but do not call <threads->isthread()>, then the child process will default to the pre-existing CORE::GLOBAL::exit() or CORE::exit() behavior. Note that such processes are exempt from application global termination if exit() is called in a thread, so you must manually clean up child processes created in this manner before exiting your threaded application. no skipping that cleanup, bestie. π§Ή
π END block behavior π
In native ithreads, END blocks are only executed in the thread in which the code was loaded/evaluated. However, in forks, END blocks are processed in all threads that are aware of such code segments (i.e. threads started after modules with END blocks are loaded). This may be considered a bug or a feature depending on what your END blocks are doing, such as closing important external resources for which each thread may have its own handle. π€
In general, it is a good defensive programming practice to add the following to your END blocks when you want to insure they only are evaluated in the thread that they were created in:
{
my $tid = threads->tid if exists $INC{'threads.pm'};
END {
return if defined($tid) && $tid != threads->tid;
# standard end block code goes here
}
}
This code is completely compatible with native ithreads. Note that this behavior may change in the future (at least with THREADS_NATIVE_EMULATION mode). iykyk πΈ
π₯ Modifying signals π₯
Since the threads API provides a method to send signals between threads (processes), untrapped normal and error signals are defined by forks with a basic exit() shutdown function to provide safe termination. π
Thus, if you (or any modules you use) modify signal handlers, it is important that the signal handlers at least remain defined and are not undefined (for whatever reason). The system signal handler default, usually abnormal process termination which skips END blocks, may cause undesired behavior if a thread exits due to an unhandled signal. so like, don't ghost your signal handlers. π»
In general, the following signals are considered "safe" to trap and use in threads (depending on your system behavior when such signals are trapped):
HUP INT PIPE TERM USR1 USR2 ABRT EMT QUIT TRAP
π Modules that modify %SIG or use POSIX::sigaction() π
To insure highest stability, forks ties some hooks into the global %SIG hash to co-exist as peacefully as possible with user-defined signals. This has a few subtle, but important implications:
- As long as you modify signals using
%SIG, you should never encounter any unexpected issues. - If you use
POSIX::sigaction, it may subvert protections thatforkshas added to the signal handling system. In normal circumstances, this will not create any run-time issues; however, if you also attempt to access shared variables in signal handlers orENDblocks, you may encounter unexpected results. Note: if you do usesigaction, please avoid overloading theABRTsignal in the main thread, as it is used for process group flow control.
bestie, that ABRT note is not a vibe suggestion, it's a real caveat. π
π¦ Modules that modify $SIG{CHLD} π¦
In order to be compatible with perl's core system() function on all platforms, extra care has gone into implementing a smarter $SIG{CHLD} in forks.pm. The only functional effect is that you will never need to (or be able to) reap threads (processes) if you define your own CHLD handler. π
You may define the environment variable THREADS_SIGCHLD_IGNORE to force forks to use 'IGNORE' on systems where a custom CHLD signal handler has been automatically installed to support correct exit code of perl core system() function. Note that this should not be necessary unless you encounter specific issues with the forks.pm CHLD signal handler.
π $thr->wantarray() returns void after $thr->join or $thr->detach π
Be aware that thread return context is purged and $thr->wantarray will return void context after a thread is detached or joined. This is done to minimize memory in programs that spawn many (millions of) threads. This differs from default threads.pm behavior, but should be acceptable as the context no longer serves a functional purpose after a join or detach. Thus, if you still require thread context information after a join, be sure to request and store the value of $thr->wantarray first. π
β $thr->get_stack_size() returns default after $thr->join or $thr->detach β
Thread stack size information is purged and $thr->get_stack_size will return the current threads default after a thread is detached or joined. This is done to minimize memory in programs that spawn many (millions of) threads. This differs from default threads.pm behavior, which retains per-thread stack size information indefinitely. Thus, if you require individual thread stack size information after a join or detach, be sure to request and store the value of $thr->get_stack_size first. π§
π Modules that modify CORE::GLOBAL::fork() π
This modules goes to great lengths to insure that normal fork behavior is seamlessly integrated into the threaded environment by overloading CORE::GLOBAL::fork. Thus, please refrain from overloading this function unless absolutely necessary. In such a case, forks.pm provides a set of four functions:
_fork_pre
_fork
_fork_post_parent
_fork_post_child
that represent all possible functional states before and after a fork occurs. These states must be called to insure that fork() works for both threads and normal fork calls. π§
Refer to forks.pm source code, *CORE::GLOBAL::fork = sub { ... } definition as an example usage. Please contact the author if you have any questions regarding this. π«Ά
β¨ CAVEATS β¨
Some caveats that you need to be aware of. yes bestie, we're still in the fine print, but it's important fine print. π
πΈ Greater latency πΈ
Because of the use of sockets for inter-thread communication, there is an inherent larger latency with the interaction between threads. However, the fact that TCP sockets are used, may open up the possibility to share threads over more than one physical machine. π
You may decrease some latency by using UNIX sockets (see "UNIX socket support").
Also, you may wish to try forks::BerkeleyDB, which has shown signifigant performance gains and consistent throughoutput in applications requiring high-concurrency shared variable access. π₯
π Module CLONE & CLONE_SKIP functions and threads π
In rare cases, module CLONE functions may have issues when being auto-executed by a new thread (forked process). This only affects modules that use XS data (objects or struts) created by to external C libraries. If a module attempts to CLONE non-fork safe XS data, at worst it may core dump only the newly created thread (process). π
If CLONE_SKIP function is defined in a package and it returns a true value, all objects of this class type will be undefined in new threads. This is generally the same behavior as native threads with Perl 5.8.7 and later. See perlmod (http://perldoc.perl.org/perlmod.html#Making-your-module-threadsafe-threadsafe-thread-safe-module%2c-threadsafe-module%2c-thread-safe-CLONE-CLONE_SKIP-thread-threads-ithread) for more information. π
However, two subtle behavior variances exist relative to native Perl threads:
- The actual undefining of variables occurs in the child thread. This should be portable with all non-perl modules, as long as those module datastructures can be safely garbage collected in the child thread (note that
DESTROYwill not be called). - Arrays and hashes will be emptied and unblessed, but value will not be converted to an undef scalar ref. This differs from native threads, where all references become an undef scalar ref. This should be generally harmless, as long as you are careful with variable state checks (e.g. check whether reference is still blessed, not whether the
reftypehas changed, to determine if it is still a valid object in a new thread).
Overall, if you treat potentially sensitive resources (such as DBI driver instances) as non-thread-safe by default and close these resources prior to creating a new thread, you should never encounter any portability issues. π‘οΈ
π Can't return unshared filehandles from threads π
Currently, it is not possible to return a file handle from a thread to the thread that is joining it. Attempting to do so will throw a terminal error. However, if you share the filehandle first with forks::shared, you can safely return the shared filehandle. π«Ά
π Signals and safe-signal enabled Perl π
In order to use signals, you must be using perl 5.8 compiled with safe signal support. Otherwise, you'll get a terminal error like "Cannot signal threads without safe signals" if you try to use signal functions. no cap, that's the literal error. π
π§ Source filter π§
To get forks.pm working on Perl 5.6.x, it was necessary to use a source filter to ensure a smooth upgrade path from using forks under Perl 5.6.x to Perl 5.8.x and higher. The source filter used is pretty simple and may prove to be too simple. Please report any problems that you may find when running under 5.6.x. π’
β¨ TODO β¨
See the TODO file in the distribution. π
β¨ KNOWN PROBLEMS β¨
These problems are known and will hopefully be fixed in the future:
π test-suite exits in a weird way π
Although there are no errors in the test-suite, the test harness sometimes thinks there is something wrong because of an unexpected exit() value. This is an issue with Test::More's END block, which wasn't designed to co-exist with a threads environment and forked processes. Hopefully, that module will be patched in the future, but for now, the warnings are harmless and may be safely ignored. π
And of course, there might be other, undiscovered issues. Patches are welcome! π«Ά
β¨ CREDITS β¨
Refer to the "CREDITS" file included in the distribution. π
β¨ CURRENT AUTHOR AND MAINTAINER β¨
Eric Rybski <rybskej@yahoo.com>. Please send all module inquries to me. π¬
β¨ ORIGINAL AUTHOR β¨
Elizabeth Mattijsen, <liz@dijkmat.nl>. π
π COPYRIGHT π
Okay bestie, the legal bit, and it's actually cute so pay attention:
- Copyright (c) π
2005-2014β Eric Rybski<rybskej@yahoo.com>2002-2004β Elizabeth Mattijsen<liz@dijkmat.nl>
All rights reserved. Like, all of them, fr fr.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. That's the whole vibe β same license as Perl, no extra hoops, iconic behavior. π«Ά
π SEE ALSO π
The lil friend group of related modules, go read these next:
threadsforks::BerkeleyDBApache::forks
lowkey a whole journey and you made it to the end of the manpage?? main character energy for real. now go make some forks, bestie π
That's the whole page, down to the footer, which tells you you're reading perl v5.42.3 and that this beauty was dated 2026-08-20 β so if you're reading it on anything older than that, consider this your sign to update. π
forks(3pm) β that's a wrap, periodt. β¨ π¦ πΈ
π¦ where this page comes from
- ubuntu stonking: libforks-perl 0.36-3build6 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms