Perl多进程与信号量

一、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
时间: 2024-11-05 12:15:12

Perl多进程与信号量的相关文章

多用户多进程互斥信号量的问题

问题描述 目前有两个进程A用户:a进程:asp.netv4.0(IIS用户):w3wp.exe进程这两个进程会同时访问数据库,所以利用CreateMutex创建一个互斥变量,为了适用多用户第三个参数加了Global\的变量,并且两个进程都提升了SE_CREATE_GLOBAL_NAME权限.目前的问题:如果先打开a进程,此时a进程首先创建互斥变量,再打开w3wp.exe进程,w3wp.exe进程进程访问不了该互斥变量.如果先打开w3wp.exe进程变量,此时w3wp.exe进程先创建互斥变量,再

毕业设计想做一些linux C编程,大家有什么既简单又有创意的点子吗?

问题描述 大家好,本人今年大四,网络工程专业的学生,毕业设计想做一些linux C编程,百度到一篇帖子[http://zhidao.baidu.com/question/231233146.html],觉得不太合适,所以想借此机会征求征求大家的意见.自己曾想着写一个Boot Loader(灵感来源于这样的经历:自己曾大致了解了x86架构下,从按下电源按钮开始,Linux系统开机启动流程),后来想了想,觉得一个人写的话难度太大,加之又有其他一些优秀的类似工具,如grub等等,另外还要忙着找工作--

perl信号量实现进程间通信

开篇   近期在给一个客户编写数据库迁移工具,语言使用的是不太熟悉的perl.而需要做进程间通信源自这样一个需求,即并行迁移,想要真正的提升性能,我没有选择多线程的方式,而是直接选择多进程.   而我们都知道,多进程和多线程的区别就在于多进程的稳定性,多进程的内存资源是独立的,而多线程确实和父进程共享的.场景图示如下,   描述一下,首先通过简单的算法,将表大致平均地分到多个子进程,每个子进程任务完成后统计成功的表数量.那么统计表数量的变量就是关键了,在这里多个进程是需要共享这个变量的   li

什么是多线程和多进程

  线程和进程都是现在电脑概念里比较时髦的用语,什么是多线程,什么是多进程?本文详细的给您介绍一下,希望能增进您对当代电脑技术的了解,有不到之处,还往高手予以更正.进程(英语:Process,中国大陆译作进程,台湾译作行程)是计算机中已运行程序的实体.进程本身不会运行,是线程的容器.程序本身只是指令的集合,进程才是程序(那些指令)的真正运行.若干进程有可能与同一个程序相关系,且每个进程皆可以同步(循序)或不同步(平行)的方式独立运行.进程为现今分时系统的基本运作单位 线程(英语:thread,台

Linux下多进程/多线程编程

linux下多进程.多线程编程 linux下进程   (一) 理解Linux下进程的结构  Linux下一个进程在内存里有三部份的数据,就是"数据段","堆栈段"和"代码段",其实学过汇编语言的人一定知道,一般的CPU象I386,都有上述三种段寄存器,以方便操作系统的运行."代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段.  堆栈段存放的就是子程序的返回地址

qt-QT多进程和多线程区别

问题描述 QT多进程和多线程区别 5C 目前有一个项目,之前是VxWorks系统下Tornado开发的,一共四个任务.分别为采集数据.数据处理.串口传输.界面显示.现在要转换成Linux下用Qt开发.我现在已经用QT的多线程方式完成了整个项目,但是被要求用进程.那么问题来了:1:请问QT的多线程是不是可以理解成Linux下的多进程?2:如果不是,那么请问Qt下怎么进行多进程编程?进程之间的通信同步互斥什么的Qt有没有提供支持的类?还是得用Linux下的消息队列.管道.信号量什么的?3:如果有大神

Linux下多进程编程(C语言)

Linux下多进程编程(C语言) 一.    进程简介 1.进程是程序的执行.程序是静态的,进程是动态的. 2.进程在内存中有三部分组成:数据段.堆栈段和代码段.          代码段:就是存放程序代码的数据,如果有数个进程运行同一个一个程序,那么它们就可以使用同一个代码段(代码段是可以共享的):          堆栈段:存放的是子程序的返回地址.参数以及程序的局部变量,主要是保存进程的执行的环境,这里用到了栈先进后出的特性,可以看做具有记忆上一次执行的环境.          数据段:存

Python多进程编程技术实例分析_python

本文以实例形式分析了Python多进程编程技术,有助于进一步Python程序设计技巧.分享给大家供大家参考.具体分析如下: 一般来说,由于Python的线程有些限制,例如多线程不能充分利用多核CPU等问题,因此在Python中我们更倾向使用多进程.但在做不阻塞的异步UI等场景,我们也会使用多线程.本篇文章主要探讨Python多进程的问题. Python在2.6引入了多进程的机制,并提供了丰富的组件及api以方便编写并发应用.multiprocessing包的组件Process, Queue, P

perl脚本学习指南--读书笔记_应用技巧

undef 默认未定义字符,perl里面没有NULL,defined($x)函数:如果参数为undef返回false qw(cs phy geo) 类似于 ("cs", "phy", "geo")列表可以赋值给数组@array 数组操作符:pop,push操作末尾,shift,unshift操作开头,reverse逆序,@array = sort @array; foreach @array{print $_;}打印数组:$_是一个很强大的默认变