perl信號量實現進程間通信
開篇
近期在給一個客戶編寫數據庫遷移工具,語言使用的是不太熟悉的perl。而需要做進程間通信源自這樣一個需求,即並行遷移,想要真正的提升性能,我沒有選擇多線程的方式,而是直接選擇多進程。
而我們都知道,多進程和多線程的區別就在於多進程的穩定性,多進程的內存資源是獨立的,而多線程確實和父進程共享的。場景圖示如下,
描述一下,首先通過簡單的算法,將表大致平均地分到多個子進程,每個子進程任務完成後統計成功的表數量。那麼統計表數量的變量就是關鍵了,在這裏多個進程是需要共享這個變量的
linux下的進程間通信,共有三個媒介,消息隊列、共享內存段以及信號量。通常共享內存段和信號量配合使用,而這裏我們隻需要做簡單的 持鎖+計數+釋鎖,這麼說來,此場景下信號量就是個天然的計數器了。
這三種媒介可以使用ipcs命令查看,
使用
如下代碼示例,
#!/usr/bin/perl
use IPC::SysV qw(S_IRWXU IPC_CREAT);
use IPC::Semaphore;
my $sem0;
my $sem1;
my @childs;
my $sem = IPC::Semaphore->new(1556, 1, S_IRWXU|IPC_CREAT)
|| die "IPC::Semaphore->new: $!\n";
##創建一個信號量集,1556是key,1是信號量的個數,S_IRWXU即700權限,IPC_CREAT沒有則創建
$sem->setval(0,0);
##設置初始值,這裏隻有一個信號量則下標為0,初始值為0
for ($i=0; $i<5; $i++){
if($pid=fork())
{
$childs[$i] = $pid;
}elsif(defined $pid){
sleep(1);
$sem->op(0, +1, SEM_UNDO);
##op方法通過semop來調用係統PV原子操作,子進程退出時會通過 SEM_UNDO 來解鎖
exit;
}else{
print "Error!\n";
exit;
}
}
for $p (@childs){
waitpid($p, 0);
}
$sem1 = $sem->getval(0);
##獲取信號量值
print $sem1."\n";
其中涉及到的幾個常用方法如下,
new ( KEY , NSEMS , FLAGS )
Create a new semaphore set associated with KEY . NSEMS is the number of semaphores in the set. A new set is created if
● KEY is equal to IPC_PRIVATE
● KEY does not already have a semaphore identifier associated with it, and FLAGS & IPC_CREAT is true.
On creation of a new semaphore set FLAGS is used to set the permissions. Be careful not to set any flags that the Sys V IPC implementation does not allow: in some systems setting execute bits makes the operations fail.
setval ( N , VALUE )
Set the N th value in the semaphore set to VALUE
op ( OPLIST )
OPLIST is a list of operations to pass to semop. OPLIST is a concatenation of smaller lists, each which has three values. The first is the semaphore number, the second is the operation and the last is a flags value.
getval ( SEM )
Returns the current value of the semaphore SEM .
輸出結果如下
[root@mysqltest2 testconfig]# perl sem.pl
5
[root@mysqltest2 testconfig]#
銷毀
執行完成之後,再使用ipcs命令查看信號量集。
614轉換成十進製數,即256*6+16*1+4=1556,並且權限是700,這個信號量是不是很熟悉呢?
由於使用了IPC_CREAT這個flag,因此我們注釋掉初始化操作,再執行一下程序看看。如下
my $sem = IPC::Semaphore->new(1556, 1, S_IRWXU|IPC_CREAT)
|| die "IPC::Semaphore->new: $!\n";
#$sem->setval(0,0);
執行結果如下,
[root@mysqltest2 testconfig]# perl sem.pl
10
[root@mysqltest2 testconfig]#
從輸出結果我們看到,由於信號量一直存在因此沒有重新創建,PV操作也是基於上一次的結果繼續進行的。
再次執行,
[root@mysqltest2 testconfig]# perl sem.pl
15
[root@mysqltest2 testconfig]#
remove方法。官方解釋如下,
remove
Remove and destroy the semaphore set from the system.
那麼意義很明顯,就是用來銷毀信號量的。我們在代碼尾部添加銷毀語句,
$sem->remove();
再次執行結果如下,
[root@mysqltest2 testconfig]# perl sem.pl
20
[root@mysqltest2 testconfig]#
然後查看信號量,發現已經被銷毀了
那麼現在再執行,信號量就應該是重新創建了,
[root@mysqltest2 testconfig]# perl sem.pl
5
[root@mysqltest2 testconfig]#
執行結果完全符合。最後兩次的執行首先基於舊的信號量做操作,因此執行完畢時信號量值為20,然後銷毀掉信號量,下次執行重新創建,因此最後一次的值為5。
結語
隻是幾句簡單的代碼,卻幫了我的大忙,理解至上。
最後更新:2017-08-13 22:34:05