Vous êtes sur la page 1sur 6

blog | file s | sm fale rt | black box

SMF Monitor Ale rt v1

Update 2 C om panion C D

Perl fork() for idiots


Forking in perl is a nice thing to do, and for some its a hard thing to understand. It can be pretty easy to get lost especially since there are 100 ways to the same thing. Im going to attempt to explain a little bit of the inner workings of fork() in Perl. First you have to understand what fork() returns. When you do: my $pid = fork(); If it is the parent, $pid will be assigned the PID of the child. If it is the child, $pid will be assigned 0. If it cannot fork anymore because of no resources, $pid will be undefined. To help show how a fork() program works, Im going to use this sample script:

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

#!/usr/bin/perl my $pid = fork(); if (not defined $pid) { print resources not avilable.\n; } elsif ($pid == 0) { print IM THE C HILD\n; sleep 5; print IM THE C HILD2\n; exit(0); } else { print IM THE PARENT\n; waitpid($pid,0); } print HIYA\n; If run, you will see this: $ ./f.pl IM THE C HILD IM THE PARENT - sleep for 5 seconds IM THE C HILD2 HIYA $ ps -ef | grep fork1.pl derek 6440 2888 0 15:45 pts/2 00:00:00 /usr/bin/perl ./fork1.pl derek 6441 6440 0 15:45 pts/2 00:00:00 /usr/bin/perl ./fork1.pl This is a pretty simple script and self explanatory. It starts out with the fork and then checks the value of $pid through the if statements and executes the block of code accordingly. What you really have to understand is that when fork() is called, you now have 2 programs that are the same. So in this example, when we do my $pid = fork(); you now have 2 processes running. Each process will run the code. It looks like $pid is only being assigned one value here but it is actually being assigned two or even three values (undefined if necessary). When the parent runs checking through the if statements, it will catch on the last else statement here because $pid is assigned PID of the child. When the child runs through this block of code, it will catch on the if ($pid == 0) because the $pid is assigned 0 for a child. The waitpid() call just waits for the child to exit. If you do not do this it will become

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

waitpid() call just waits for the child to exit. If you do not do this it will become a zombie (defunct) process, which means it has become detached from its parent. So here is exactly what happens when you run this: - The program forks, you now have 2 processes, one is the child, one is the parent. - if (not defined $pid) gets run on both processes, and dies if resources arent available. - elsif ($pid == 0) gets run on both processes, if its the child, print IM THE C HILD, sleep for 5 seconds and then print IM THE C HILD 2 and exit(0); - While the above statement is running on the child, the parent is going along with the else {} block of code and prints IM THE PARENT and then waits for the child to exit. NOTE: The exit(0) in the child block is very important.. you need the child to exit its process when it is done, so it will no longer exist. Now for another example using fork.. here is fork2.pl: #!/usr/bin/perl @array = qw(shit fuck blah test smith bob homes point); $num = 5; for(1..$num) { my $pid = fork(); if ($pid) { # parent waitpid($pid,0); } elsif ($pid == 0) { # child print @array\n; exit(0); } else { die couldnt fork: $!\n; } print LAST IN FOR\n; } print AFTER FOR\n; This is pretty much like the above code except I switched up the if statements

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

This is pretty much like the above code except I switched up the if statements (they mean the same thing though) and added a few things. This code says, for 1 to 5, fork, and if its the parent wait on the child, if its the child print @array and exit. Running it you get something like this: # ./fork2.pl shit fuck blah LAST IN FOR shit fuck blah LAST IN FOR shit fuck blah LAST IN FOR shit fuck blah LAST IN FOR shit fuck blah LAST IN FOR AFTER FOR test smith bob homes point test smith bob homes point test smith bob homes point test smith bob homes point test smith bob homes point

With the print statements it shows you how it works through the loop. One thing to keep in mind here though is that you arent creating 5 parents and 5 childs. You are creating 1 parent and 5 childs. The parent is waiting for the childs to get done and the childs are printing @array. And to prove that I show it here with a little Dtrace: # dtrace -n syscall::fork1:entry { @[execname] = count(); } dtrace: description syscall::fork1:entry matched 1 probe ^C bash 1 fork2.pl 5 There is also some more cool stuff you can do with Perl and Dtrace mentioned here. Now say you want to fork a process and each one will take a while to finish.. you dont want to have to wait for them each one at a time, you want them to all work in the background. We didnt see this before because in the fork2.pl each print @array that the child was doing takes very very very little time to do. To emulate this, put sleep 5 in this same fork2.pl under the child after the print, so we will be saying each child will take 5 seconds to finish. Heres what you get:

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

# ./fork2.pl shit fuck blah test smith - sleep for 5 seconds LAST IN FOR shit fuck blah test smith - sleep for 5 seconds LAST IN FOR shit fuck blah test smith - sleep for 5 seconds LAST IN FOR shit fuck blah test smith - sleep for 5 seconds LAST IN FOR shit fuck blah test smith - sleep for 5 seconds LAST IN FOR AFTER FOR

bob homes point

bob homes point

bob homes point

bob homes point

bob homes point

This would be wrong because you are waiting for the childs one at a time to finish. You want to be able to have them spawn off 5 and wait for them at the same time, here is what you want.. fork3.pl: #!/usr/bin/perl @array = qw(shit fuck blah test smith bob homes point); $num = 10; for(1..$num) { my $pid = fork(); if ($pid) { # parent push(@childs, $pid); } elsif ($pid == 0) { # child print @array\n\n; sleep 5; exit(0); } else { die couldnt fork: $!\n;

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

die couldnt fork: $!\n; } print BEFORE FOR BRAC KET\n; } print AFTER FOR BRAC KET\n; foreach (@childs) { waitpid($_, 0); } This says for 1 to 10, fork, and if parent then add $pid (pid of the child) to @childs array, if child print @array sleep for 5 seconds and exit. Then at the bottom says for each pid in @childs, wait for it to finish. In this you would have 11 processes, 1 parent and 10 childs. By playing with the above examples anyone can learn how this works.. its not very hard at all once you understand and it finaly clicks in your head. There arent many good places explaining forking so hopefully this will be some use.

This entry was posted on Thursday , August 10th, 2006 at 2:15 pm and is f iled under General. Y ou can f ollow any responses to this entry through the RSS 2.0 f eed. Responses are currently closed, but y ou can trackback f rom y our own site.

C om m e nts are close d.

Total Visitors: 756,755 e -m ail: dacrud@gm ail.com

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

Vous aimerez peut-être aussi