PHP Conference Japan 2024

sem_acquire

(PHP 4, PHP 5, PHP 7, PHP 8)

sem_acquire取得號誌

說明

sem_acquire(SysvSemaphore $semaphore, bool $non_blocking = false): bool

預設情況下,sem_acquire() 會阻斷(如有必要),直到可以取得號誌為止。如果取得號誌將導致其達到的號誌最大數量被超過,則嘗試取得其已取得之號誌的行程將永遠阻斷。

處理請求後,行程取得但未明確釋放的任何號誌將會自動釋放,並產生警告。

參數

semaphore

semaphore 是從 sem_get() 取得的號誌。

non_blocking

指定程序是否不應等待信號量被取得。如果設為 true,則在無法立即取得信號量時,呼叫將立即返回 false

回傳值

成功時返回 true,失敗時返回 false

更新日誌

版本 說明
8.0.0 semaphore 現在需要一個 SysvSemaphore 實例;以前需要一個 resource

參見

新增註釋

使用者貢獻的註釋 7 則註釋

gladd at trash dot eris dot qinetiq dot com
20 年前
只是為了澄清上面「程序」的含義

在 Apache 網頁伺服器上,許多 PHP 請求會在同一個程序空間內執行,因為它是多執行緒的。然而,任何被腳本取得和獲取但未釋放和移除的信號量,每次腳本終止時仍會被 PHP 直譯器自動清除。

寄送電子郵件前請移除任何垃圾郵件!
Pinky
12 年前
sem_acquire() 是阻塞的,這意味著使用相同信號量的後續呼叫將無限期阻塞,直到信號量被釋放。這確保了序列化,但如果您只想檢查是否應該繼續,這並不是很實用。遺憾的是,PHP 尚未支援以非阻塞方式查詢信號量狀態的任何方法。

使用共享記憶體(shm_ 函數)似乎可以手動組裝這樣一個機制。但是,請注意,這並不容易,而且最終沒有效率。例如,您不能簡單地選擇一個共享記憶體變數,儲存信號量鍵並查詢它。這樣的操作將是非事務性和非原子的,例如,兩個或多個平行程序有可能在其中一個程序設法將其標記為「已鎖定」之前,設法從共享記憶體變數中讀取「未鎖定」。您必須使用(阻塞)信號量來序列化對共享記憶體變數的存取,從而重新產生您正試圖解決的問題。

換句話說,如果非阻塞查詢對您至關重要,您需要要求 PHP 設計者解決此問題,或者選擇另一種機制來進行鎖定,一種已經具有此功能的機制。
Sander Backus
11 年前
請注意,當您重設 $sem_identifier 時,信號量將不再阻塞!

這段程式碼無效
$key = ftok(__FILE__,'m');
$a = sem_get($key);
sem_acquire($a);
$a = false;

而這段程式碼有效

$key = ftok(__FILE__,'m');
$a = sem_get($key);
sem_acquire($a);
//$a = false;

所以:使用獨特的變數名稱作為你的識別符號!
arjuna w
12 年前
在我的測試中,sem_acquire() 比 flock() 快 150 倍
Ben
4 年前
我最近不得不使用信號量來避免同時執行資料庫更新。

為了測試它,我在同一個桌面上使用了兩個瀏覽器視窗(Chrome)。

在這種情況下,信號量沒有按預期工作。
同樣,對檔案使用 flock 鎖定也沒有按預期工作。

從命令列執行指令碼確實按預期工作。

一旦我使用兩個不同的瀏覽器,一個在我的桌面上,另一個在虛擬機器中,它就會像預期一樣工作。

希望這可以幫助任何人避免關於這個主題的奇怪除錯過程...
anatoliy at ukhvanovy dot name
9 年前
如果您需要非阻塞信號量,以下是如何實現它的一個範例。使用一個共享記憶體變數來標記鎖是否存在,然後在針對該變數的操作周圍使用信號量。我將我的共享變數稱為「token」。

<?php
echo '<pre>';

$resourceSemaphore = sem_get(7);
$tokenSemaphore = sem_get(8);
$tokenValue = shm_attach(9, 100);

function
myEcho($v) {
echo
microtime() . ' ' . $v . "\n";
}

// sem_remove($resourceSemaphore);
// sem_remove($tokenSemaphore);
// exit();

function try_lock() {
global
$resourceSemaphore, $tokenSemaphore, $tokenValue;
myEcho('begin try_lock()');
myEcho('acquire token semaphore');
sem_acquire($tokenSemaphore);
myEcho(' token semaphore acquired');
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token value: ' . var_export($tmp, true));
$exit = $tmp;
if (!
$exit) {
$tmp = shm_put_var($tokenValue, 6, true);
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token new value: ' . var_export($tmp, true));
}
myEcho('release token semaphore');
sem_release($tokenSemaphore);
if (
$exit) return false;
myEcho('acquire resource semaphore');
sem_acquire($resourceSemaphore);
myEcho(' resource semaphore acquired');
return
true;
}

function
release() {
global
$resourceSemaphore, $tokenSemaphore, $tokenValue;
myEcho('release resource semaphore');
sem_release($resourceSemaphore);
myEcho('acquire token semaphore');
sem_acquire($tokenSemaphore);
myEcho(' token semaphore acquired');
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token value: ' . var_export($tmp, true));
$tmp = shm_put_var($tokenValue, 6, false);
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token new value: ' . var_export($tmp, true));
myEcho('release token semaphore');
sem_release($tokenSemaphore);
}

for (
$triesLeft = 5; $triesLeft > 0 && !try_lock(); $triesLeft--) {
myEcho('failed to acquire resource');
myEcho('wait for 1 sec');
sleep(1);
myEcho('try again');
}
myEcho(' access the resource for 4 sec');
//paste here your code, accessing your resource
sleep(4);
release();
myEcho('the end');
?>
When I execute this script in two parallel instances, I get the following output
-------(第一個實例)----------------------------------------
... 482 開始 try_lock()
... 482 取得 token 信號量
... 482 token 信號量已取得
... 482 token 值:false
... 482 token 新值:true
... 482 釋放 token 信號量
... 482 取得資源信號量
... 482 資源信號量已取得
... 482 訪問資源 4 秒
... 486 釋放資源信號量
... 486 取得 token 信號量
... 486 token 信號量已取得
... 486 token 值:true
... 486 token 新值:false
... 486 釋放 token 信號量
... 486 結束
-------(第二個實例)----------------------------------------
... 485 開始 try_lock()
... 485 取得 token 信號量
... 485 token 信號量已取得
... 485 token 值:true
... 485 釋放 token 信號量
... 485 無法取得資源
... 485 等待 1 秒
...
... 486 等待 1 秒
... 487 再次嘗試
... 487 開始 try_lock()
... 487 取得 token 信號量
... 487 token 信號量已取得
... 487 token 值:false
... 487 token 新值:true
... 487 釋放 token 信號量
... 487 取得資源信號量
... 487 資源信號量已取得
... 487 訪問資源 4 秒
... 491 釋放資源信號量
... 491 取得 token 信號量
... 491 token 信號量已取得
... 491 token 值:true
... 491 token 新值:false
... 491 釋放 token 信號量
... 491 結束
anatoliy at ukhvanovy dot name
9 年前
很遺憾,PHP 目前不支援非阻塞信號量。

如果需要這樣做,您可以利用信號量 (Semaphore) 和共享內存 (Shared Memory) 來創建您自己的非阻塞鎖定機制。

使用共享內存變量來標記鎖是否存在,然後在針對該變量的操作周圍使用信號量。
To Top