SHM 在 Windows 中本身并不可用,因此 PHP 试图通过在内部使用 Windows 文件映射在其“线程安全资源管理器”(TSRM) 中模拟它,这是一个丑陋的 hack (/TSRM/tsrm_win32.c)。
因此,shmop 扩展也将 TSRM 用于 Windows 系统上的 SHM。
与命令一起shmop_delete()
使用来标记内存段被销毁,但是在仿真中是通过以下方式实现的:shmctl()
IPC_RMID
IPC_RMID
switch (cmd) {
[...]
case IPC_RMID:
if (shm->descriptor->shm_nattch < 1) {
shm->descriptor->shm_perm.key = -1;
}
return 0;
段所附加的进程数在哪里shm_nattch
(或至少 TSRM 认为它是什么数)。通过设置shm_perm.key
为 -1,后续访问shmget()
将被阻止,直到 Windows 文件映射被破坏。但是,当从 调用此代码时shmop_delete()
,至少始终有 PHP 进程本身附加到内存段,因此它实际上什么都不做。该段仅在您调用后分离shmop_close()
所以你的答案是:如果不修复 PHP,在 Windows 上,你不能删除共享内存。
您可以将其归咎于 TSRM 中的 SHM 仿真,这不是完全正确的,也可以归咎于 shmop 扩展以盲目使用它。
您可以尝试无条件地删除if
and 设置为 -1 并重新编译 PHP。shm_perm.key
它只能破坏 shmop 扩展本身、sysvshm 扩展或可能其他未随 PHP 分发的扩展。
随时向http://bugs.php.net/上的 PHP bugtracker 报告该问题,并由更熟悉 PHP 内部结构的人修复。
与此同时,也许http://www.php.net/w32api会有所帮助 - 您可以更直接地使用 Win32-API 中的 CreateFileMapping 和朋友。但是,我从未测试过它,并且在 PECL 中它说它没有被维护,所以要小心。它当然也不是便携式的。
您还可以尝试将这些shmop_*
东西包装到您自己的库中,并将您自己的已删除标志放在内存段的开头——毕竟 TSRM 在内部做了类似的事情。但是你可能会遇到一个相关的错误:我想我记得有人报告说他无法创建一个shmop_open()
比使用相同密钥创建的最后一个段更大的段。