PHP Conference Japan 2024

訊號量函式

目錄

新增註解

使用者貢獻的註解 6 則註解

11
elran70 at hotmail dot com
22 年前
使用此處大多數函式的範例程式碼

$MEMSIZE = 512;// 要配置的共享記憶體大小
$SEMKEY = 1; // 訊號量金鑰
$SHMKEY = 2; // 共享記憶體金鑰

echo "開始。\n";
// 取得訊號量
$sem_id = sem_get($SEMKEY, 1);
if ($sem_id === false)
{
echo "取得訊號量失敗";
exit;
}
else
echo "取得訊號量 $sem_id.\n";

// 取得訊號量
if (! sem_acquire($sem_id))
{
echo "取得訊號量 $sem_id 失敗。\n";
sem_remove($sem_id);
exit;
}
else
echo "成功取得訊號量 $sem_id.\n";

$shm_id = shm_attach($SHMKEY, $MEMSIZE);
if ($shm_id === false)
{
echo "連接共享記憶體失敗。\n";
sem_remove($sem_id);
exit;
}
else
echo "成功連接共享記憶體:$shm_id.\n";

// 寫入變數 1
if (!shm_put_var($shm_id, 1, "變數 1"))
{
echo "在共享記憶體 $shm_id 上放置變數 1 失敗。\n";
sem_remove($sem_id);
shm_remove ($shm_id);
exit;
}
else
echo "將變數 1 寫入共享記憶體。\n";

// 寫入變數 2
if (!shm_put_var($shm_id, 2, "變數 2"))
{
echo "在共享記憶體 $shm_id 上放置變數 2 失敗。\n";
sem_remove($sem_id);
shm_remove ($shm_id);
exit;
}
else
echo "將變數 2 寫入共享記憶體。\n";

// 讀取變數 1
$var1 = shm_get_var ($shm_id, 1);
if ($var1 === false)
{
echo "從共享記憶體 $shm_id 檢索變數 1 失敗,傳回值=$var1.\n";
}
else
echo "讀取變數 1=$var1.\n";

// 讀取變數 1
$var2 = shm_get_var ($shm_id, 2);
if ($var1 === false)
{
echo "從共享記憶體 $shm_id 檢索變數 2 失敗,傳回值=$var2.\n";
}
else
echo "讀取變數 2=$var2.\n";

// 釋放訊號量
if (!sem_release($sem_id))
echo "釋放訊號量 $sem_id 失敗。\n";
else
echo "訊號量 $sem_id 已釋放。\n";

// 從 SysV 中移除共享記憶體區段
if (shm_remove ($shm_id))
echo "已成功從 SysV 移除共享記憶體。\n";
else
echo "從 SysV 移除 $shm_id 共享記憶體失敗。\n";

// 移除訊號量
if (sem_remove($sem_id))
echo "已成功從 SysV 移除訊號量。\n";
else
echo "從 SysV 移除 $sem_id 訊號量失敗。\n";
echo "結束。\n";
2
hekkwan at gmail dot com
18 年前
我一直在嘗試讓一個 PHP 主控台腳本和一個 C 應用程式使用一個共同的訊號量一段時間。我剛剛讓它運作了,所以我認為我應該在此貼上程式碼,以防有人需要這樣做,但是,這裡不是長程式碼範例的地方

我使用 PHP 實作中的 C 程式碼來設定訊號量集合,然後模擬 PHP 解譯器實作 mutext 型鎖定方案的方式,使用一個共同的 semop 呼叫。

必須以與 PHP 實作相同的方式進行處理,否則您可能會冒著 PHP 解譯器為您重設訊號量集合的風險。

基本概念是。
1) sem_get - 使用三個訊號量集合
1.1) 遞增第一個訊號量
1.2) 檢查使用計數 (訊號量 3),如果只有一個,使用訊號量 2 為互斥行為將 max_attach 設定為訊號量 3
2) 遞減訊號量 1
3) 對於鎖定/解除鎖定,請使用第一個訊號量,但始終從您的 C 程式碼中呼叫上述內容。

如果您想要我的程式碼副本,請發送電子郵件給我,我很樂意將其發送給您!
1
chrissavery at removeme dot gmail dot com
18 年前
我對兩個事情感到困惑,這兩個事情導致我在 Apache 下執行 PHP 腳本時使用訊號量時出現奇怪的行為。

通常,頁面請求最終會與其他同時請求由相同的程序填寫。因此,當您可能沒有預期時,訊號量會被封鎖。

另請注意,sem_remove() 將為所有進程移除它,而不僅僅是呼叫進程。因此,您必須確保最後一個執行的進程移除訊號量,而不是之前的進程。當我的子進程因錯誤而退出時,我認為發生了一些故障。

因此,您不能只在一個將被 Web 使用者命中的腳本中使用 get、acquire、release、remove。(1) 它們可能會在同一個進程中結束,並會等待另一個,並且 (2) 第一個完成的進程會為其他進程銷毀訊號量。

我省略了 remove 呼叫,它運作良好,但我仍然想知道當最後一個執行 get 的腳本完成時,訊號量是否會被 PHP 移除?此外,建立一個子進程使用 proc_open 來執行工作可以確保單獨的進程,但要小心,您還希望以某種方式限制數量。
1
php at stolt dot de
24 年前
sem_get() 和 shm_attach() 的整數金鑰必須在系統範圍內是唯一的。沒有方法可以確保系統上的其他進程不會使用您的特定金鑰(安全性!和可能的故障)。此外,很少使用共享記憶體,存在衝突的可能性!要查看已使用的 ID,您可以使用程式 'ipcs'(至少在 SuseLinux 下;)。謝謝 Christian C.
1
hcuevas at galenicom dot com
21 年前
不要使用訊號量來序列化對未定義數量資源的存取。在鎖定之前,沒有辦法(尚未)知道訊號量是否已被鎖定,因此無法完全釋放訊號量,並在未定義的時間內佔用訊號量資源。

一個可能的解決方案是建立一個共享記憶體池,並在那裡儲存訊號量 ID 的目前鎖定數量。

乾杯,
Horaci Cuevas
1
Roman Laptev <tmp at laptev dot org>
21 年前
如果您要使用一些外部程式建立的訊號量,您可以嘗試以下程式碼(C 範例)

#define SVSEM_MODE (SEM_R | SEM_A | SEM_R>>3 | SEM_R>>6) /* 0644 */
#define PHP_SEM_NEED_NUMBER 3

/*.......*/
int semid, semflag = SVSEM_MODE | IPC_CREAT | IPC_EXCL;
struct sembuf semptr;
union semun semopts;
/*.......*/
if( (semid = semget(sempath, PHP_SEM_NEED_NUMBER, semflag)) >= 0 ) {
semopts.val = 1; /* 訊號燈的初始值 */
if( semctl( semid, 0, SETVAL, semopts) < 0 ) {/*錯誤*/}
if( semctl( semid, 1, SETVAL, semopts) < 0 ) {/*錯誤*/}
/* PHP 希望將第三個訊號燈的值設為 0,用於其自身的 semget。
* 請參考 ./PHP_SOURCE_PATH/ext/sysvsem/sysvsem.c */
*/
semopts.val = 0;
if( semctl( semid, 2, SETVAL, semopts) < 0 ) {/*錯誤*/}
}
else if(errno == EEXIST) { /* 僅連接 */
if( (semid = semget(sempath, PHP_SEM_NEED_NUMBER, SVSEM_MODE | IPC_CREAT)) < 0 ) {/*錯誤*/}
}
else {/*錯誤*/}

/*.......*/
/* 如果您想要取得訊號燈 */
semptr.sem_num = 0;
semptr.sem_op = -1; /* 鎖定 */
semptr.sem_flg = SEM_UNDO;
while( semop(semid, &semptr, 1) < 0 ) {/*錯誤*/}
/*.......*/

感謝,
Roma
To Top