PHP 文件鎖與進程鎖

鑒于前面介紹了swoole,就借用swoole的服務(wù)器/客戶端與多進程機制對進行說明.
這里只針對PHP的鎖機制進行說明,由于SQL的鎖與其作用方式和應(yīng)用場景不同,將作另行說明.

1.文件鎖

flock()
fclose()
swoole_lock()

文件鎖的可能應(yīng)用場景為:

  • 1.限制并發(fā)多進程或多臺服務(wù)器需要對同一文件進行訪問和修改;
  • 2.對參與文件I/O的進程隊列化和人為阻塞;
  • 3.在業(yè)務(wù)邏輯中對文件內(nèi)容進行守護;

**下面是文件鎖C/S通訊機制下的使用,已經(jīng)省略了具體的通訊過程,如有需要請移步swoole異步任務(wù)隊列 **
Server(服務(wù)器通訊過程已略):

//監(jiān)聽數(shù)據(jù)發(fā)送事件
$serv->on('receive', function ($serv, $fd, $from_id, $data) {
    $serv->send($fd, "ServerEnd");

    $p_file = "locktest.txt";
    var_dump(file_get_contents($p_file));
});

Client1(服務(wù)器通訊過程已略):

$s_recv = "ww";

$p_file = "locktest.txt";

$o_file = fopen($p_file,'w+');
// flock()加鎖方式:
flock($o_file,LOCK_EX);

// // swoole加鎖方式:
// $lock = new swoole_lock(SWOOLE_FILELOCK, $p_file);
// $lock->lock();

fwrite($o_file, 'ss' . $s_recv);

sleep(30);
// 兩種解鎖方式
// flock($o_file, LOCK_UN);
// $lock->unlock();

Client2(服務(wù)器通訊過程已略):


$s_recv = "xx";

$p_file = "locktest.txt";

$o_file = fopen($p_file,'w+');
// flock()加鎖方式:
flock($o_file,LOCK_EX);

// // swoole加鎖方式:
// $lock = new swoole_lock(SWOOLE_FILELOCK, $p_file);
// $lock->lock();


fwrite($o_file, 'ss' . $s_recv);

// 兩種解鎖方式
// flock($o_file, LOCK_UN);
// $lock->unlock();

結(jié)果:
Client2被阻塞了30s,直到Client1執(zhí)行結(jié)束才對文件進行了一次寫入;

[l0.16@4 m29.5% c30s04] $ php swoole_client2.php

需要注意的是:

  • 1.無論是flock()還是swoole提供的swoole_lock(),都有在進程結(jié)束時自動解鎖的機制,所以在demo中即使不進行手動解鎖也能正常運行,因此這里在第一個Client中執(zhí)行了sleep()暫停函數(shù)來觀察文件鎖的效果;
  • 2.flock()的標(biāo)準(zhǔn)釋放方式為flock($file,LOCK_UN);, 但是個人喜歡fclose(),永絕后患;

2.進程鎖

與文件鎖不同的是,進程鎖并不用于阻止對文件的I/O,而是用于防止多進程并發(fā)造成的預(yù)期之外的后果.所以需要在多進程并發(fā)時將其隊列化,即在某進程的關(guān)鍵邏輯執(zhí)行結(jié)束前阻塞其他并發(fā)進程的邏輯執(zhí)行.

實現(xiàn)思路有幾種:

  • 1.利用flock()文件鎖,創(chuàng)建一個臨時lock文件,使用LOCK_NB模擬阻塞或非阻塞流,再在進程內(nèi)部使用判定條件控制邏輯執(zhí)行;

    非阻塞模型demo:

$p_file = "locktest.txt";
$o_file = fopen($p_file, 'w+');

// 如果臨時文件被鎖定,這里的flock()將返回false
if (!flock($o_file, LOCK_EX + LOCK_NB)) {
    var_dump('Process Locked');
}
else {
    // 非阻塞模型必須在flock()中增加LOCK_NB參數(shù)
    // 當(dāng)然,這里取消LOCK_NB參數(shù)就是阻塞模型了
    flock($o_file, LOCK_EX + LOCK_NB);
    var_dump('Process Locking');
    // 模擬長時間的執(zhí)行操作
    sleep(10);
}
  • 2.利用swoole提供的共享內(nèi)存,緩存方法或通信方法在不同的進程中傳遞一個全局變量,進程獲取該變量的狀態(tài)后使用判定條件控制邏輯執(zhí)行;

    傳遞變量的方法很多,這里只提供一個思路,就以memcached為例;
    阻塞模型demo:

// 初始化memcached
$memcached = new Memcache;
$memcached->connect("localhost", 11211);

// 獲取用來做狀態(tài)判定的全局變量
$s_flag = $memcached->get("flag");

if (!$s_flag) {
    // 這里利用了memcached的過期時間作為演示,實際上業(yè)務(wù)處理完成后銷毀該變量即可
    $memcached->set("flag", "locked", 0, 10);
    main();
}
else {
    // 阻塞模型
    while ($s_flag == 'locked') {
        var_dump('Process locked, retrying...');
        // 設(shè)置重試時間, 避免過于頻繁的操作嘗試
        sleep(1);
        // 更新狀態(tài)變量
        $s_flag = $memcached->get("flag");
    }
    // // 非阻塞模型
    // if ($s_flag == 'locked') {
    //     var_dump('Process locked, suspended');
    //     die();
    // }
    main();
}

// 模擬業(yè)務(wù)主函數(shù)
function main() {
    var_dump('Process Running');
    // 業(yè)務(wù)執(zhí)行結(jié)束后回收memcached
    // $memcached->delete("flag");
}

這里需要注意的是:
1.memcached的過期時間不可少于程序運行的實際時間,因此建議稍微長一點,邏輯執(zhí)行結(jié)束后進行回收;
2.在非阻塞模型中,若狀態(tài)被判定為false,應(yīng)該將進程中止或block,避免業(yè)務(wù)邏輯的繼續(xù)執(zhí)行;
3.在實際應(yīng)用中,設(shè)置一個重試時間很有必要,這樣可以很大程度上減少針對memcached的大量I/O并發(fā),減輕服務(wù)器壓力;

下次討論SQL的鎖及其應(yīng)用.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末多艇,一起剝皮案震驚了整個濱河市年局,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扒最,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贤姆,死亡現(xiàn)場離奇詭異渔欢,居然都是意外死亡,警方通過查閱死者的電腦和手機色迂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門香缺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人歇僧,你說我怎么就攤上這事图张。” “怎么了诈悍?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵祸轮,是天一觀的道長。 經(jīng)常有香客問我侥钳,道長适袜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任舷夺,我火速辦了婚禮苦酱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冕房。我一直安慰自己躏啰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布耙册。 她就那樣靜靜地躺著给僵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪详拙。 梳的紋絲不亂的頭發(fā)上帝际,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音饶辙,去河邊找鬼蹲诀。 笑死,一個胖子當(dāng)著我的面吹牛弃揽,可吹牛的內(nèi)容都是我干的脯爪。 我是一名探鬼主播则北,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼痕慢!你這毒婦竟也來了尚揣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤掖举,失蹤者是張志新(化名)和其女友劉穎快骗,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塔次,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡方篮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了励负。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藕溅。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖继榆,靈堂內(nèi)的尸體忽然破棺而出蜈垮,到底是詐尸還是另有隱情,我是刑警寧澤裕照,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布攒发,位于F島的核電站,受9級特大地震影響晋南,放射性物質(zhì)發(fā)生泄漏惠猿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一负间、第九天 我趴在偏房一處隱蔽的房頂上張望偶妖。 院中可真熱鬧,春花似錦政溃、人聲如沸趾访。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扼鞋。三九已至,卻和暖如春愤诱,著一層夾襖步出監(jiān)牢的瞬間云头,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工淫半, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留溃槐,地道東北人科吭。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓猴鲫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谣殊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容