閱讀800 返回首頁    go iPhone_iPad_Mac_apple


perl信號量實現進程間通信

開篇

  近期在給一個客戶編寫數據庫遷移工具,語言使用的是不太熟悉的perl。而需要做進程間通信源自這樣一個需求,即並行遷移,想要真正的提升性能,我沒有選擇多線程的方式,而是直接選擇多進程。
  而我們都知道,多進程和多線程的區別就在於多進程的穩定性,多進程的內存資源是獨立的,而多線程確實和父進程共享的。場景圖示如下,
today1
  描述一下,首先通過簡單的算法,將表大致平均地分到多個子進程,每個子進程任務完成後統計成功的表數量。那麼統計表數量的變量就是關鍵了,在這裏多個進程是需要共享這個變量的

  linux下的進程間通信,共有三個媒介,消息隊列、共享內存段以及信號量。通常共享內存段和信號量配合使用,而這裏我們隻需要做簡單的 持鎖+計數+釋鎖,這麼說來,此場景下信號量就是個天然的計數器了。
  這三種媒介可以使用ipcs命令查看,
today2

使用

如下代碼示例,

#!/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命令查看信號量集。
today3
  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]#

然後查看信號量,發現已經被銷毀了
today4
那麼現在再執行,信號量就應該是重新創建了,

[root@mysqltest2 testconfig]# perl sem.pl 
5
[root@mysqltest2 testconfig]#

  執行結果完全符合。最後兩次的執行首先基於舊的信號量做操作,因此執行完畢時信號量值為20,然後銷毀掉信號量,下次執行重新創建,因此最後一次的值為5。

結語

  隻是幾句簡單的代碼,卻幫了我的大忙,理解至上。

最後更新:2017-08-13 22:34:05

  上一篇:go  一起來讀Greenplum/Deepgreen執行計劃
  下一篇:go  block循環引用解決