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 "将变量 1 放入共享内存 $shm_id 失败。\n";
sem_remove($sem_id);
shm_remove ($shm_id);
exit;
}
else
echo "将变量 1 写入共享内存。\n";

// 写入变量 2
if (!shm_put_var($shm_id, 2, "变量 2"))
{
echo "将变量 2 放入共享内存 $shm_id 失败。\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 解释器实现互斥类型锁定方案的方式,使用公共 semop 调用。

必须以与 php 实现中相同的方式执行此过程,否则您有风险让 php 解释器为您重置信号量集。

基本思想是。
1) sem_get - 使用三个信号量集
1.1) 增加第一个信号量
1.2) 检查使用计数(sem 3),如果只有一个,则将最大附加使用 sem 2 设置为互斥行为到 sem 3
2) 减小 sem 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希望在第三个信号量上获得零值。*/
/* 请查看 ./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