信号量函数

目录

添加注释

用户贡献的注释 6 个注释

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";
hekkwan at gmail dot com
17 年前
我一直试图让一个 PHP 控制台脚本和一个 C 应用程序使用一个通用的信号量。我刚把它弄好了,所以我想我会在这里粘贴代码,以防有人需要这样做,但是,这不是长代码示例的地方

我使用了 PHP 实现中的 C 代码来设置信号量集,然后模仿 PHP 解释器实现互斥类型锁定方案的方式,使用通用的 semop 调用。

必须以与 PHP 实现中相同的方式执行该过程,否则你将冒 PHP 解释器为你重置信号量集的风险。

基本思路是。
1) sem_get - 使用一个三信号量集
1.1) 增加第一个信号量
1.2) 检查使用计数(信号量 3),如果只有一个,则将最大连接使用信号量 2 设置为互斥行为以用于信号量 3
2) 减少信号量 1
3) 对于锁定/解锁,使用第一个信号量,但始终从你的 C 代码中调用上述内容。

如果你想要我的代码副本,请给我发邮件,我会很乐意将其发送给你!
chrissavery at removeme dot gmail dot com
18 年前
我对两件事感到困惑,这两件事导致我在 Apache 下运行的 PHP 脚本中使用信号量时出现奇怪的行为。

通常,页面请求最终将由与其他同时请求相同的进程处理。因此,信号量将在你可能没有预期的时候阻塞。

还要注意,sem_remove() 将为所有进程删除它,而不仅仅是调用进程。因此,你必须确保最后一个运行的进程删除了信号量,而其他任何进程都不会这样做。我认为我的子进程出现错误时会发生一些故障。

因此,你不能在将被 Web 用户访问的脚本中只使用 get、acquire、release 和 remove。(1)它们可能最终在同一个进程中,并且会等待对方,以及(2)第一个完成的进程将为其他进程销毁信号量。

我省略了 remove 调用,它工作正常,但我仍然想知道当最后一个执行了 get 的脚本完成时,信号量是否会由 PHP 删除?另外,使用 proc_open 创建子进程来执行工作可以确保不同的进程,但为了安全起见,你可能还想限制它们的數量。
php at stolt dot de
23 年前
sem_get() 和 shm_attach() 的整数键必须在系统范围内唯一。没有方法可以确保系统上的任何其他进程都不会使用你的特定键(安全!以及可能的故障)。另外,很少使用共享内存,存在冲突的可能性!要查看使用的 ID,可以使用程序 'ipcs'(至少在 SuseLinux 下;))。感谢 Christian C。
hcuevas at galenicom dot com
20 年前
不要使用信号量来序列化对未定义数量资源的访问。没有办法(目前)在锁定之前知道信号量是否已被锁定,因此无法完全释放信号量,并占用信号量资源以供不确定的时间。

一种可能的解决方案是构建一个共享内存池,并在其中存储信号量 ID 的当前锁定数量。

干杯,
Horaci Cuevas
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 希望第三个信号量为零以进行自身 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 ) {/* 错误 */}
/*.......*/

谢谢,
罗马
To Top