5

我已经实现了用于插入用于预订服务的数据库表的访问控制。它可以正常工作一段时间,然后sem_get()尽管我sem_release()在每个sem_get().

case 'room':
    $key = "room";
    $semaphore = sem_get($key, 1, 0666, 1);
    if ($semaphore) {
        sem_acquire($semaphore);
        //do some stuff
        if ($already_reserved_rooms < $max_rooms) {
            $return="ok";
            sem_release($semaphore);
            return $return;
        }
          sem_release($semaphore);
    }
    else {
      //send me mail that semaphore failed 
    }

    return 'no rooms';
    break;

sem_remove()也应该打电话吗?

我按照这个网站上的步骤。

4

3 回答 3

3

删除信号量

是的,您应该sem_remove()在完成信号量集后调用。否则,信号量集将保留在系统中,直到您将其删除。但是,信号量集持续存在的事实不会导致任何问题,而信号量的数量小于SEMMNS限制:

SEMMNS信号量数量的系统范围限制:取决于策略(在 Linux 上,可以通过 的第二个字段读取和修改此限制 /proc/sys/kernel/sem)。

sem_remove()立即删除信号量集,唤醒使用此信号量阻塞的所有进程。

顺便说一句,您可以使用该ipcrm命令从命令行中删除信号量,并使用该ipcs命令显示有关 IPC 设施(包括信号量)的信息。

释放信号量

sem_release()当自动释放标志(sem_get的第 4 个参数)打开时,您不需要调用。但是,只要您不需要获得的“锁”,就释放信号量是个好主意。

sem_release()只增加内部信号量的值。将其视为解锁操作,与sem_acquire().

sem_get()失败

sem_get()函数FALSE在以下情况下返回

  • PHP参数解析失败(E_ERROR);
  • 信号量存在,但调用进程无权访问set( E_WARNING);
  • 内存分配错误(E_WARNING);
  • 信号量集的最大数量,或系统范围的最大信号量数量超过 ( E_WARNING)

在每种情况下都会sem_get记录错误或警告。因此,您必须检查日志才能找出问题的根源。

由于您的代码工作了一段时间,这不是参数解析问题,也不是权限问题。内存分配问题很少见。因此,您很可能已超出信号量数量限制。查看手册页以semget供参考。手册页描述了如何通过 阅读和修改限制/proc/sys/kernel/sem

有关扩展内部的更多信息,请参阅此答案。sysvsem

于 2016-11-03T11:47:37.680 回答
2

在您的情况下,该sem_get函数返回 false,因为您给出的是字符串而不是整数。

代替

$semaphore = sem_get($key, 1, 0666, 1);

经过

$semaphore = sem_get(crc32($key), 1, 0666, 1);

它会工作

于 2019-05-13T15:06:04.173 回答
1

sem_get() 的 $key 参数是整数,而您将其作为字符串传递。请考虑通过 ftok() 调用获取整数键。

所以请考虑更换

$key = "room";

到以下代码:

$project = "r"; // Project identifier. This must be a one character string.
$key = ftok(__FILE__, $project);
于 2017-04-21T20:27:47.003 回答