Perl进程间数据共享
本文介绍的Perl进程间数据共享内容主体来自于《Pro Perl》的第21章。 IPC简介通过fork创建多个子进程时,进程间的数据共享是个大问题,要么建立一个进程间通信的通道,要么找到一个两进程都引用的共享变量。本文将介绍Unix IPC的近亲System V IPC:message queues(消息队列)、semaphores(信号量)和shared memory-segments(共享内存段)。它们都是IPC结构,它们被非常广泛地应用于进程间通信。它们的帮助文档可参见: $ perldoc IPC::Msg $ perldoc IPC::Semaphore $ perldoc IPC::SharedMem 但是,并非所有操作系统都支持System V IPC,对于那些不遵守POSIX规范的平台就不支持。当然,也并非一定要在Unix操作系统上才能使用IPC,只要操作系统支持IPC就可以,而且就算是Unix系统上也并非一定支持IPC,可以使用 $ ipcs ------ Message Queues -------- key msqid owner perms used-bytes messages ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status ------ Semaphore Arrays -------- key semid owner perms nsems message queues、semaphores和shared memory segments的共同点在于它们的数据都持久存在于内存中,且只要知道资源的ID且有权限访问,就可以被任意一个进程(所以随意多个进程)访问到。由于数据在内存中持久,且数据资源进行了ID标识,这可以使得程序退出前保存状态,然后重启时再次获取到原来的状态。 严格地说,Perl支持的IPC在于可以调用一些IPC函数:msgctl、msgget、msgrcv、msgsnd、semctl、semget、semop、shmctl、shmget、shmread、shmwrite。它们几乎是对C对应函数的封装,非常底层。尽管这些函数的文档非常丰富,但这些函数并不容易使用, IPC::SysV模块要使用IPC的一些函数,常常需要导入一些 use IPC::SysV: 它里面定义了很多常量,完整的可参见 Message Queue(消息队列)曾经消息队列是进程间通信的唯一有效方式,它就像管道一样,一端写入一端读取。对于消息队列而言,我们写入和读取的数据都称之为消息(message)。 可以创建两种类型的消息队列:私有的(private)和公有的(public)
例如,创建一个私有的消息队列。 use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRWXU); use IPC::Msg; my $queue = IPC::Msg->new IPC_PRIVATE S_IRWXU | IPC_CREAT;
权限部分也可以写成数值格式的: my $queue = IPC::Msg->new IPC_PRIVATE 0700 | IPC_CREAT; 所以,这里创建的私有队列只有创建者进程和子进程可以执行读写执行的操作。 如果想要创建一个公有队列,需要为该公有队列提供一个资源ID,资源ID是一个数值。下例中给的资源ID是10023,权限是0722,表示创建队列的进程拥有读写执行操作,而资源所在组或其它用户进程只能写队列。 my $q = IPC::Msg->new 10023,0722 | IPC_CREAT; 如果其它进程想要访问这个公有队列,只需通过new方法指定这个公有队列的KEY即可即表示构建这个已有的队列,不要指定 my $q = IPC::Msg->new 10023,0200; 而对于私有队列,想要知道它的KEY,可以使用id()方法: $KEY = $queue->id 发送和接收消息队列有了消息队列的对象结构之后,就可以操作这个消息队列,比如发送消息,接收消息等。相关文档参见 向队列发送消息和从队列中接收消息的方式为: $queue->snd($type,$wr_msg,[ $flags ]); $queue->rcv($rd_msg,$length,$type,[ $flags ]);
关于rcv type和flag的规则,参考如下解释。 rcv Type的解释: 整数值 意义 ----------------------------- 0 rcv总是读取队列的第一条消息,无视type >0 rcv总是读取该类型的第一条消息。例如, type=2,则只读取type=2的消息,如果不存在, 则一直阻塞直到有type=2的消息。但是可以设 置IPC_NOWAIT和MSG_EXCEPT常量改变这种模式 <0 rcv读取类型不大于type绝对值(从小到大)的第 一条消息。不严谨,但可看示例描述:如果rcv的 type=-2,则首先读取type=0的第一条消息,如 果不存在type=0的消息,则继续读取type=1的第 一条消息,不存在则继续读取type=2的第一条消息 flag的解释: flag值 意义 ------------------------------ MSG_EXCEPT rcv读取第一条非type值的消息。例如,rcv 的type=1,则读取第一条type不为1的消息 MSG_NOERROR 允许消息过长超过$length时截断超出的部分, 而不是在这种情况下返回E2BIG错误 IPC_NOWAIT rcv在请求的消息类型不存在时不要阻塞等待, 而是立即返回,且设置$!的值为EAGAIN 将上面的解释合并起来,很明确的意思是我们可以通过设置不同的type来实现多级通信的消息队列,这一切都交给我们自己来决定,例如对不同子进程或线程发送不同的消息。 获取和设置消息队列的属性可以使用 例如: $queue->set( uid => $user_id,# chown gid => $group_id,# chgrp mode => $perm,# 8进制权限位或S_格式的权限 qbytes => $queue_size,# 队列最大容量(capacity) ); 另外,可以使用 my $stat = $queue->stat; $stat->mode(0722); $queue->set($stat); 最后,如果拥有队列的执行权限,可以通过 $queue->remove; 如果无法删除队列,则remove返回undef,并设置 信号量和共享内存待续 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |