sem_get

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

sem_get获取信号量 ID

描述

sem_get(
    int $key,
    int $max_acquire = 1,
    int $permissions = 0666,
    bool $auto_release = true
): SysvSemaphore|false

sem_get() 返回一个 ID,该 ID 可用于访问具有给定 key 的 System V 信号量。

对同一 key 的 sem_get() 的第二次调用将返回不同的信号量标识符,但这两个标识符都访问相同的底层信号量。

如果 key0,则每次调用 sem_get() 时都会创建一个新的私有信号量。

参数

key

max_acquire

可以同时获取信号量的进程数量设置为 max_acquire

permissions

信号量权限。实际上,此值仅在进程发现它是当前唯一附加到信号量的进程时才会设置。

auto_release

指定在请求关闭时是否应该自动释放信号量。

返回值

成功时返回一个正信号量标识符,失败时返回 false

变更日志

版本 描述
8.0.0 成功时,此函数现在返回一个 SysvSemaphore 实例;以前,返回一个 resource
8.0.0 auto_release 的类型已从 int 更改为 bool

备注

警告

使用 sem_get() 访问在 PHP 外部创建的信号量时,请注意信号量必须已作为一组 3 个信号量创建(例如,通过在调用 C semget() 函数时指定 3 作为 nsems 参数),否则 PHP 将无法访问信号量。

参见

添加注释

用户贡献的注释 10 个注释

3
Dan East
3 年前
请注意,默认权限参数是八进制的!因此,默认值 0666 与 666 或 0x666 不相同。

如果将权限指定为十进制 666,那么您最终会获得阻止读取信号量的权限。症状是您只能 sem_get 一次,后续的 sem_get 将失败(直到您 ipcrm 或 sem_remove 它并完全删除它)。

因此,这些都等效于默认值
sem_get ( 123, 1, 0666)
sem_get ( 123, 1, 438)
sem_get ( 123, 1, 0x1b6)

大多数 PHP 开发人员(包括我自己)很少使用八进制数字,因此数字 0666 很容易被误认为是 666 或者可能是 0x666。
12
soger
13 年前
实际上,看起来信号量不是在请求关闭时自动释放的,而是在存储其资源 ID 的变量被释放时自动释放的。这是一个很大的区别。
6
kakkau at grr dot la
8 年前
当设置 $key = 0 时,可以创建“无限”数量的信号量。

多次运行 sem_get
php > sem_get(0,0);

并检查输出
$ ipcs -s

------ 信号量数组 --------
key semid owner perms nsems
0x00000000 1277952 user 666 3
0x00000000 1310721 user 666 3

如您所见,有多个信号量设置为 key 0。
对于任何其他整数,sem_get 按预期工作。它返回另一个指向先前创建的信号量的资源 ID,并且不会创建另一个信号量。
1
kakkau at grr dot la
8 年前
对于在使用由 sem_get() 生成的资源上使用 sem_acquire() 时遇到奇怪行为的人。查看 sem_get() 的第 4 个参数 auto_release。它允许通过重新分配到资源变量进行多次获取。

./multi.acquire.php
<?php
class Sem {
private
$key = null;
private
$res = null;
public function
__construct() {
$this->key = ftok(".",".");
$this->set_res();
$this->acquire();
}
public function
set_res() {
// 第 4 个参数 auto_released 默认值为 1
$this->res = sem_get($this->key, 1, 0600, 1);
}
public function
acquire() {
echo
"acquired='".sem_acquire($this->res,true)."'\n";
}
}

$s = new Sem();
$s->set_res();
$s->acquire();

?>

$ php multi.acquire.php
acquired='1'
acquired='1'

要避免默认情况下重新获取,请将 sem_get() 的参数 auto_release 设置为 0 或检查您的资源变量是否已设置,例如,通过使用 is_null()。
1
Michael Z.
12 年前
当您使用 fileinode() 获取唯一的信号量键(如某些关于此函数或相关函数的评论中建议的那样)与版本控制软件一起使用时要小心:例如,SVN 似乎会更改 inode。使用此类文件会导致您的互斥锁无法可靠地工作,并且您的系统信号量池将被填满,直到进一步尝试获取信号量失败。使用 linux-util-ng 中的 ipcs 和 ipcrm 命令(在大多数发行版上可能)来检查/修复相关问题。
1
neofutur
17 年前
1
joeldg at listbid.com
21 年前
<?
// 感谢
// http://www.ecst.csuchico.edu/~beej/guide/ipc/shmem.html
$SHM_KEY = ftok("/home/joeldg/homeymail/shmtest.php", 'R');
$shmid = sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
$data = shm_attach($shmid, 1024);

$data = "test";
printf("共享内容: %s\n", $data);

shm_detach($data);
?>
0
joeldg AT listbid.com
21 年前
呵呵,实际上我添加的上面的评论在技术上是不正确的,它更像是一个展示函数的想法。

$SHM_KEY = ftok("/home/joeldg/homeymail/shmtest.php", 'R');
$shmid = sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
$data = shm_attach($shmid, 1024);
// 我们现在有了我们的 shm 段

// 让我们在那里放置一个变量
shm_put_var ($data, $inmem, "test");
// 现在让我们把它取回来。我们可以在一个派生进程中,仍然可以访问这个变量。
// 访问这个变量。
printf("共享内容:%s\n", shm_get_var($data, $inmem));

shm_detach($data);
-1
ein at anti-logic dot com
17 年前
请注意,即使设置了 max_acquire=1,也无法确保对锁的独占访问。

例如,
<?
$fp = sem_get(fileinode('lock_file', 100);
sem_acquire($fp);

$fp2 = sem_get(fileinode('lock_file', 1);
sem_acquire($fp2);
?>

这不会在第二个 sem_acquire 上阻塞。因此,如果您有使用共享锁(>1 max_acquire)的函数或进程,您仍然需要为写访问提供单独的锁机制(例如 flock),这使得 sem_ 函数变得毫无用处。

更多信息,在 flock 中,每个对锁文件的引用都有其自己的选项(可以是共享的、独占的、阻塞的、非阻塞的等等),但显然 php 的 sem 函数仅支持每个信号量这些选项,而不是每个信号量引用。
-5
cyrus dot drive at gmail dot com
16 年前
在 PHP 中实现读写信号量

<?php
class rw_semaphore {

const
READ_ACCESS = 0;
const
WRITE_ACCESS = 1;

/**
* @access private
* @var resource - 互斥信号量
*/
private $mutex;

/**
* @access private
* @var resource - 读写信号量
*/
private $resource;

/**
* @access private
* @var int
*/
private $writers = 0;

/**
* @access private
* @var int
*/
private $readers = 0;

/**
* 默认构造函数
*
* 初始化读写信号量
*/
public function __construct() {
$mutex_key = ftok('/home/cyrus/development/php/sysvipc/rw_semaphore.php', 'm');
$resource_key = ftok('/home/cyrus/development/php/sysvipc/rw_semaphore.php', 'r');
$this->mutex = sem_get($mutex_key, 1);
$this->resource = sem_get($resource_key, 1);
}

/**
* 析构函数
*
* 删除读写信号量
*/
public function __destruct() {
sem_remove($this->mutex);
sem_remove($this->resource);
}

/**
* 请求对资源的访问
*
* @param int $mode
* @return void
*/
private function request_access($access_type = self::READ_ACCESS) {
if (
$access_type == self::WRITE_ACCESS) {
sem_acquire($this->mutex);

/* 更新写入器计数器 */
$this->writers++;

sem_release($this->mutex);
sem_acquire($this->resource);
} else {
sem_acquire($this->mutex);
if (
$this->writers > 0 || $this->readers == 0) {
sem_release($this->mutex);
sem_acquire($this->resource);
sem_acquire($this->mutex);
}
/* 更新阅读器计数器 */
$this->readers++;

sem_release($this->mutex);
}
}

private function
request_release($access_type = self::READ_ACCESS) {
if (
$access_type == self::WRITE_ACCESS) {
sem_acquire($this->mutex);

/* 更新写入器计数器 */
$this->writers--;

sem_release($this->mutex);
sem_release($this->resource);
} else {
sem_acquire($this->mutex);

/* 更新阅读器计数器 */
$this->readers--;

if (
$this->readers == 0)
sem_release($this->resource);

sem_release($this->mutex);
}
}

/**
* 请求对资源的读访问
*
* @return void
*/
public function read_access() { $this->request_access(self::READ_ACCESS); }

/**
* 释放对资源的读访问
*
* @return void
*/
public function read_release() { $this->request_release(self::READ_ACCESS); }

/**
* 请求对资源的写访问
*
* @return void
*/
public function write_access() { $this->request_access(self::WRITE_ACCESS); }

/**
* 释放对资源的写访问
*
* @return void
*/
public function write_release() { $this->request_release(self::WRITE_ACCESS); }

}
?>
To Top