Perl多进程与信号量

    xiaoxiao2023-07-03  164

    一、Perl多进程

    今天这里就不多说什么是多进程、什么是多线程了,简单来说目的都是充分利用硬件资源,最大化机器性能。任何语言的新手在遇到多进程编程时,心里往往会发怵,多进程好像很高大上、好复杂的样子,其实不然。我们要区分多进程实现本身和多进程应用编程,多进程本身的实现确实是很复杂的,但是我们更多的是集中在多进程应用编程,这部分就比较简单了。话不多说,下面先看用perl实现的一个多进程编程例子。

    #!/bin/perl use strict; # fork returns the child pid to parent, 0 to child or undef if failed to fork. my $pid = fork(); die "fork failed" unless defined $pid; if($pid > 0){ my $i = 1000; while($i > 0){ print "parent process i = $i\n"; $i--; } }elsif($pid == 0){ my $i = 1000; while($i > 0){ print "child process i = $i\n"; $i--; } }

    上述例子中,实现多进程最关键的方法就是fork,其功能是将当前代码完全拷贝一份,也就是形成两份相同的程序:父进程和子进程。其中,在父进程中,fork的返回值是子进程的进程号(大于0的值);而在子进程中,fork返回值是0;fork失败时返回的值为负数。fork失败的情况一般是资源耗尽,我自己在编程时遇到过几次,都是fork太多的进程耗尽了系统资源。通过以上三个返回值,我们就能确定fork有没有成功,以及成功时谁是父进程、谁是子进程,这样就可以决定在父进程或者子进程中做什么样的操作。例子中父、子进程都是循环输出1000至1,同时给出父子进程提示信息。输出结果如下:

    parent process i = 36 child process i = 254 parent process i = 35 child process i = 253 parent process i = 34 child process i = 252 parent process i = 33 child process i = 251 parent process i = 32 child process i = 250 parent process i = 31 child process i = 249 parent process i = 30 child process i = 248 parent process i = 29 child process i = 247 parent process i = 28 child process i = 246 parent process i = 27 child process i = 245 parent process i = 26 child process i = 244 parent process i = 25 child process i = 243 parent process i = 24 child process i = 242 child process i = 241 child process i = 240 parent process i = 23 child process i = 239 parent process i = 22 child process i = 238 parent process i = 21 child process i = 237 parent process i = 20 child process i = 236 parent process i = 19 child process i = 235 parent process i = 18 child process i = 234 parent process i = 17 child process i = 233 parent process i = 16 child process i = 232

    二、僵尸进程

    1、什么是僵尸进程?

    简单来讲(我最喜欢简单来讲),子进程完成使命(死了),却没有被父进程回收(收尸),什么作用都没有了,却还暂留在系统中,就像僵尸。进程变为僵尸进程时其所占用的资源都会被回收掉,因此不会造成太大的资源泄露,当然,进程本身的信息(进程号,创建时间等)还是存在的。

    2、为什么会产生僵尸进程?如何回收?

    一般情况是父进程比子进程提前结束并且没有任何其它进程来回收子进程时就会产生僵尸进程,例如我们在程序中没有指明父进程需要等待子进程全部结束并回收子进程时,子进程就会成为僵尸进程。避免产生僵尸进程需要用到wait或者waitpid函数,这里我使用的是waitpid($pid,0)函数。该函数的功能是等待$pid进程结束并回收它。代码如下:

    #!/bin/perl use strict; # fork returns the child pid to parent, 0 to child or undef if failed to fork. my $pid = fork(); die "fork failed" unless defined $pid; if($pid > 0){ my $i = 1000; while($i > 0){ print "parent process i = $i\n"; $i--; } # 等待子进程结束并回收它 waitpid($pid,0); }elsif($pid == 0){ my $i = 1000; while($i > 0){ print "child process i = $i\n"; $i--; } }

    三、信号量(进程同步)

    不需要多么仔细的观察就能发现第一个样例程序中,两个进程是并行执行的,这或许正是我们使用进程的目的。但是,有些时候,比如说两个进程都需要使用某个资源,而这个资源不能被两个进程同时使用,因此我们希望这两个进程串行执行。这个时候我们就需要使用锁这种东西来确保进程同步。在这里,我使用了IPC的信号量,并让信号量资源值为1,当资源值为1时,其作用相当于锁。

    # new一个信号量集(信号量数组,下标从0开始),第二个参数1表示该信号量集中只有一个信号量(下标为0),其它值为系统定义参数 our $sem = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR | IPC_CREAT); # 设定信号量集中下标为0的信号量资源值为1 $sem->setval(0,1); # 该操作表示P操作,请求一个资源,第一个参数表示信号量下标,中间参数表示请求一个资源,最后一个参数表示如果进程结束则直接释放资源 $sem->op(0,-1,SEM_UNDO); # 该操作表示V操作,释放一个资源 $sem->op(0,1,SEM_UNDO); # 移除信号量集,如果不移除,则信号量会一直留在系统中 $sem->remove() if defined $sem;

    Linux系统中使用ipcs -a命令可以查看当前系统中所有的信号量及共享内存段等使用。有些时候程序意外终止,信号量未释放,那么就可以使用该命令查看信号量,并使用ipcrm -s semid移除用semid标识的信号。

    完整代码如下:

    #!/bin/perl use strict; use IPC::Semaphore; use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT IPC_NOWAIT SEM_UNDO); our $sem = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR | IPC_CREAT); $sem->setval(0,1); # fork returns the child pid to parent, 0 to child or undef if failed to fork. my $pid = fork(); die "fork failed" unless defined $pid; if($pid > 0){ $sem->op(0,-1,SEM_UNDO); my $i = 1000; while($i > 0){ print "parent process i = $i\n"; $i--; } $sem->op(0,1,SEM_UNDO); }elsif($pid == 0){ $sem->op(0,-1,SEM_UNDO); my $i = 1000; while($i > 0){ print "child process i = $i\n"; $i--; } } $sem->remove() if defined $sem;

    输出结果如下,可以看到,两个进程时串行执行的,达到了进程同步的效果。

    parent process i = 16 parent process i = 15 parent process i = 14 parent process i = 13 parent process i = 12 parent process i = 11 parent process i = 10 parent process i = 9 parent process i = 8 parent process i = 7 parent process i = 6 parent process i = 5 parent process i = 4 parent process i = 3 parent process i = 2 parent process i = 1 child process i = 1000 child process i = 999 child process i = 998 child process i = 997 child process i = 996 child process i = 995 child process i = 994 child process i = 993 child process i = 992 child process i = 991 child process i = 990 child process i = 989 child process i = 988 child process i = 987 child process i = 986 child process i = 985 child process i = 984 child process i = 983 child process i = 982 child process i = 981 child process i = 980 child process i = 979 相关资源:敏捷开发V1.0.pptx
    最新回复(0)