成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PHP編程中的鎖

caikeal / 555人閱讀

摘要:編程中的鎖最近看了理解進(jìn)程這本開(kāi)源書(shū),鏈接。該書(shū)描述了中的進(jìn)程概念,對(duì)鎖和進(jìn)程間通信有一些總結(jié)。模塊中的信號(hào)量創(chuàng)建信號(hào)量刪除信號(hào)量一般不用請(qǐng)求得到信號(hào)量釋放信號(hào)量。

PHP編程中的鎖

最近看了《理解Linux進(jìn)程》這本開(kāi)源書(shū),鏈接。該書(shū)描述了linux中的進(jìn)程概念,對(duì)鎖和進(jìn)程間通信(IPC)有一些總結(jié)。不過(guò)該書(shū)的描述語(yǔ)言是golang, 平時(shí)用的比較少,就想對(duì)應(yīng)概念找找php中的接口。

文件鎖

全名叫 advisory file lock, 書(shū)中有提及。 這類鎖比較常見(jiàn),例如 mysql, php-fpm 啟動(dòng)之后都會(huì)有一個(gè)pid文件記錄了進(jìn)程id,這個(gè)文件就是文件鎖。

這個(gè)鎖可以防止重復(fù)運(yùn)行一個(gè)進(jìn)程,例如在使用crontab時(shí),限定每一分鐘執(zhí)行一個(gè)任務(wù),但這個(gè)進(jìn)程運(yùn)行時(shí)間可能超過(guò)一分鐘,如果不用進(jìn)程鎖解決沖突的話兩個(gè)進(jìn)程一起執(zhí)行就會(huì)有問(wèn)題。

使用PID文件鎖還有一個(gè)好處,方便進(jìn)程向自己發(fā)停止或者重啟信號(hào)。例如重啟php-fpm的命令為

kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

發(fā)送USR2信號(hào)給pid文件記錄的進(jìn)程,信號(hào)屬于進(jìn)程通信,會(huì)另開(kāi)一個(gè)篇幅。

php的接口為flock,文檔比較詳細(xì)。先看一下定義,bool flock ( resource $handle , int $operation [, int &$wouldblock ] ).

$handle是文件系統(tǒng)指針,是典型地由 fopen() 創(chuàng)建的 resource(資源)。這就意味著使用flock必須打開(kāi)一個(gè)文件。

$operation 是操作類型。

&$wouldblock 如果鎖是阻塞的,那么這個(gè)變量會(huì)設(shè)為1.

需要注意的是,這個(gè)函數(shù)默認(rèn)是阻塞的,如果想非阻塞可以在 operation 加一個(gè) bitmask LOCK_NB. 接下來(lái)測(cè)試一下。

$pid_file = "/tmp/process.pid";
$pid = posix_getpid();
$fp = fopen($pid_file, "w+");
if(flock($fp, LOCK_EX | LOCK_NB)){
    echo "got the lock 
";
    ftruncate($fp, 0);      // truncate file
    fwrite($fp, $pid);
    fflush($fp);            // flush output before releasing the lock
    sleep(300); // long running process
    flock($fp, LOCK_UN);    // 釋放鎖定
} else {
    echo "Cannot get pid lock. The process is already up 
";
}
fclose($fp);

保存為 process.php,運(yùn)行php process.php &, 此時(shí)再次運(yùn)行php process.php,就可以看到錯(cuò)誤提示。flock也有共享鎖,LOCK_SH.

互斥鎖和讀寫(xiě)鎖 sync模塊中的Mutex

Mutex是一個(gè)組合詞,mutual exclusion。用pecl安裝一下sync模塊, pecl install sync。 文檔中的SyncMutex只有兩個(gè)方法,lock 和 unlock, 我們就直接上代碼測(cè)試吧。沒(méi)有用IDE寫(xiě),所以cs異常丑陋,請(qǐng)無(wú)視。

$mutex = new SyncMutex("UniqueName");

for($i=0; $i<2; $i++){
    $pid = pcntl_fork();
    if($pid <0){
        die("fork failed");
    }elseif ($pid>0){
        echo "parent process 
";
    }else{
        echo "child process {$i} is born. 
";
        obtainLock($mutex, $i);
    }
}

while (pcntl_waitpid(0, $status) != -1) { 
    $status = pcntl_wexitstatus($status); 
    echo "Child $status completed
"; 
}

function obtainLock ($mutex, $i){
    echo "process {$i} is getting the mutex 
";
    $res = $mutex->lock(200);
    sleep(1);
    if (!$res){
        echo "process {$i} unable to lock mutex. 
";
    }else{
        echo "process {$i} successfully got the mutex 
";
        $mutex->unlock();
    }
    exit();
}

保存為mutex.php, run php mutex.php, output is

parent process 
parent process 
child process 1 is born. 
process 1 is getting the mutex 
child process 0 is born. 
process 0 is getting the mutex 
process 1 successfully got the mutex 
Child 0 completed
process 0 unable to lock mutex. 
Child 0 completed

這里子進(jìn)程0和1不一定誰(shuí)在前面。但是總有一個(gè)得不到鎖。這里SyncMutex::lock(int $millisecond)的參數(shù)是 millisecond, 代表阻塞的時(shí)長(zhǎng), -1 為無(wú)限阻塞。

sync模塊中的讀寫(xiě)鎖

SyncReaderWriter的方法類似,readlock, readunlock, writelock, writeunlock,成對(duì)出現(xiàn)即可,沒(méi)有寫(xiě)測(cè)試代碼,應(yīng)該和Mutex的代碼一致,把鎖替換一下就可以。

sync模塊中的Event

感覺(jué)和golang中的Cond比較像,wait()阻塞,fire()喚醒Event阻塞的一個(gè)進(jìn)程。有一篇好文介紹了Cond, 可以看出Cond就是鎖的一種固定用法。SyncEvent也一樣。
php文檔中的例子顯示,fire()方法貌似可以用在web應(yīng)用中。

上測(cè)試代碼

for($i=0; $i<3; $i++){
    $pid = pcntl_fork();
    if($pid <0){
        die("fork failed");
    }elseif ($pid>0){
        //echo "parent process 
";
    }else{
        echo "child process {$i} is born. 
";
        switch ($i) {
        case 0:
            wait();
            break;
        case 1:
            wait();
            break;
        case 2:
            sleep(1);
            fire();
            break;
        }
    }
}

while (pcntl_waitpid(0, $status) != -1) { 
    $status = pcntl_wexitstatus($status); 
    echo "Child $status completed
"; 
}

function wait(){
    $event = new SyncEvent("UniqueName");
    echo "before waiting. 
";
    $event->wait();
    echo "after waiting. 
";
    exit();
}

function fire(){
    $event = new SyncEvent("UniqueName");
    $event->fire();
    exit();
}

這里故意少寫(xiě)一個(gè)fire(), 所以程序會(huì)阻塞,證明了 fire() 一次只喚醒一個(gè)進(jìn)程。

pthreads模塊

貌似也看到了Mutex, Cond, Pool. 沒(méi)來(lái)得及看,看完再補(bǔ)充。

信號(hào)量 sync模塊中的信號(hào)量

SyncSemaphore文檔中顯示,它和Mutex的不同之處,在于Semaphore一次可以被多個(gè)進(jìn)程(或線程)得到,而Mutex一次只能被一個(gè)得到。所以在SyncSemaphore的構(gòu)造函數(shù)中,有一個(gè)參數(shù)指定信號(hào)量可以被多少進(jìn)程得到。
public SyncSemaphore::__construct ([ string $name [, integer $initialval [, bool $autounlock ]]] ) 就是這個(gè)$initialval (initial value)

$lock = new SyncSemaphore("UniqueName", 2);

for($i=0; $i<2; $i++){
    $pid = pcntl_fork();
    if($pid <0){
        die("fork failed");
    }elseif ($pid>0){
        echo "parent process 
";
    }else{
        echo "child process {$i} is born. 
";
        obtainLock($lock, $i);
    }
}

while (pcntl_waitpid(0, $status) != -1) { 
    $status = pcntl_wexitstatus($status); 
    echo "Child $status completed
"; 
}

function obtainLock ($lock, $i){
    echo "process {$i} is getting the lock 
";
    $res = $lock->lock(200);
    sleep(1);
    if (!$res){
        echo "process {$i} unable to lock lock. 
";
    }else{
        echo "process {$i} successfully got the lock 
";
        $lock->unlock();
    }
    exit();
}

這時(shí)候兩個(gè)進(jìn)程都能得到鎖。

sysvsem模塊中的信號(hào)量

sem_get 創(chuàng)建信號(hào)量

sem_remove 刪除信號(hào)量(一般不用)

sem_acquire 請(qǐng)求得到信號(hào)量

sem_release 釋放信號(hào)量。和 sem_acquire 成對(duì)使用。

$key = ftok("/tmp", "c");
$sem = sem_get($key);

for($i=0; $i<2; $i++){
    $pid = pcntl_fork();
    if($pid <0){
        die("fork failed");
    }elseif ($pid>0){
        //echo "parent process 
";
    }else{
        echo "child process {$i} is born. 
";
        obtainLock($sem, $i);
    }
}

while (pcntl_waitpid(0, $status) != -1) { 
    $status = pcntl_wexitstatus($status); 
    echo "Child $status completed
"; 
}
sem_remove($sem); // finally remove the sem

function obtainLock ($sem, $i){
    echo "process {$i} is getting the sem 
";
    $res = sem_acquire($sem, true);
    sleep(1);
    if (!$res){
        echo "process {$i} unable to get sem. 
";
    }else{
        echo "process {$i} successfully got the sem 
";
        sem_release($sem);
    }
    exit();
}

這里有一個(gè)問(wèn)題,sem_acquire()第二個(gè)參數(shù)$nowait默認(rèn)為false,阻塞。我設(shè)為了true,如果得到鎖失敗,那么后面的sem_release會(huì)報(bào)警告 PHP Warning: sem_release(): SysV semaphore 4 (key 0x63000081) is not currently acquired in /home/jason/sysvsem.php on line 33, 所以這里的release操作必須放在得到鎖的情況下執(zhí)行,前面的幾個(gè)例子中沒(méi)有這個(gè)問(wèn)題,沒(méi)得到鎖執(zhí)行release也不會(huì)報(bào)錯(cuò)。當(dāng)然最好還是成對(duì)出現(xiàn),確保得到鎖的情況下再release。

此外,ftok這個(gè)方法的參數(shù)有必要說(shuō)明下,第一個(gè) 必須是existing, accessable的文件, 一般使用項(xiàng)目中的文件,第二個(gè)是單字符字符串。返回一個(gè)int。

輸出為

parent process 
parent process 
child process 1 is born. 
process 1 is getting the mutex 
child process 0 is born. 
process 0 is getting the mutex 
process 1 successfully got the mutex 
Child 0 completed
process 0 unable to lock mutex. 
Child 0 completed

最后,如果文中有錯(cuò)誤的地方,希望大神指出,幫助一下菜鳥(niǎo)進(jìn)步,謝謝各位。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/21188.html

相關(guān)文章

  • 編程語(yǔ)言的心智負(fù)擔(dān)

    摘要:心智負(fù)擔(dān)因此在中建議使用或函數(shù)代替宏。心智負(fù)擔(dān)等編程語(yǔ)言,默認(rèn)整數(shù)為有符號(hào),降低了心智負(fù)擔(dān)。而動(dòng)態(tài)弱類型語(yǔ)言可能會(huì)因?yàn)橹貥?gòu)或其他維護(hù)操作產(chǎn)生運(yùn)行時(shí)錯(cuò)誤,增加了心智負(fù)擔(dān)。心智負(fù)擔(dān)而且異步的等無(wú)需擔(dān)心此問(wèn)題。 很多編程語(yǔ)言對(duì)比的文章,總喜歡比較各種編程語(yǔ)言的性能、語(yǔ)法、IO模型。本文將從心智負(fù)擔(dān)這個(gè)角度去比較下不同的編程語(yǔ)言和技術(shù)。因本人所擅長(zhǎng)的編程語(yǔ)言有限,如有不對(duì)的地方,歡迎指正。 內(nèi)...

    zhangke3016 評(píng)論0 收藏0
  • 并發(fā)編程中,你加的鎖未必安全

    摘要:我們知道在并發(fā)編程中,不能使用多把鎖保護(hù)同一個(gè)資源,因?yàn)檫@樣達(dá)不到線程互斥的效果,存在線程安全的問(wèn)題。兩個(gè)線程都完成轉(zhuǎn)賬操作后,的賬戶余額可能為,也可能為,但是不可能為。摘要:在編寫(xiě)多線程并發(fā)程序時(shí),我明明對(duì)共享資源加鎖了???為什么還是出問(wèn)題呢?問(wèn)題到底出在哪里呢?其實(shí),我想說(shuō)的是:你的加鎖姿勢(shì)正確嗎?本文分享自華為云社區(qū)《【高并發(fā)】高并發(fā)環(huán)境下詭異的加鎖問(wèn)題(你加的鎖未必安全)》,作者:冰...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • java多線程編程核心技術(shù) 2

    摘要:在兩個(gè)線程訪問(wèn)同一個(gè)對(duì)象中的同步方法時(shí)一定是線程安全的。當(dāng)一個(gè)線程訪問(wèn)的一個(gè)同步代碼塊時(shí),其他線程對(duì)同一個(gè)鐘所有其他同步代碼塊的訪問(wèn)被阻塞,這說(shuō)明使用的對(duì)象監(jiān)視器是一個(gè)。 非線程安全其實(shí)會(huì)在多個(gè)線程對(duì)同一個(gè)對(duì)象中的實(shí)例變量進(jìn)行并發(fā)訪問(wèn)時(shí)發(fā)生,產(chǎn)生的后果就是臟讀,也就是取到的數(shù)據(jù)其實(shí)是被更改過(guò)的。而線程安全就是以獲得的實(shí)例變量的值是經(jīng)過(guò)同步處理的,不會(huì)出現(xiàn)臟讀的現(xiàn)象。 非線程安全問(wèn)題存...

    wangxinarhat 評(píng)論0 收藏0
  • 淺談Java并發(fā)編程系列(七) —— 深入解析synchronized關(guān)鍵字

    摘要:第一個(gè)字被稱為。經(jīng)量級(jí)鎖的加鎖過(guò)程當(dāng)一個(gè)對(duì)象被鎖定時(shí),被復(fù)制到當(dāng)前嘗試獲取鎖的線程的線程棧的鎖記錄空間被復(fù)制的官方稱為。根據(jù)鎖對(duì)象目前是否處于被鎖定狀態(tài),撤銷(xiāo)偏向后恢復(fù)到未鎖定或經(jīng)量級(jí)鎖定狀態(tài)。 Synchronized關(guān)鍵字 synchronized的鎖機(jī)制的主要優(yōu)勢(shì)是Java語(yǔ)言內(nèi)置的鎖機(jī)制,因此,JVM可以自由的優(yōu)化而不影響已存在的代碼。 任何對(duì)象都擁有對(duì)象頭這一數(shù)據(jù)結(jié)構(gòu)來(lái)支持鎖...

    piglei 評(píng)論0 收藏0
  • 一起學(xué)并發(fā)編程 - 等待與通知

    摘要:如果有其它線程調(diào)用了相同對(duì)象的方法,那么處于該對(duì)象的等待池中的線程就會(huì)全部進(jìn)入該對(duì)象的鎖池中,從新?tīng)?zhēng)奪鎖的擁有權(quán)。 wait,notify 和 notifyAll,這些在多線程中被經(jīng)常用到的保留關(guān)鍵字,在實(shí)際開(kāi)發(fā)的時(shí)候很多時(shí)候卻并沒(méi)有被大家重視,而本文則是對(duì)這些關(guān)鍵字的使用進(jìn)行描述。 存在即合理 在java中,每個(gè)對(duì)象都有兩個(gè)池,鎖池(monitor)和等待池(waitset),每個(gè)...

    Meathill 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<