php 的 Semaphore扩展为System V IPC系列功能提供包装,包括信号量,共享内存和进程间消息传递(IPC)。
1、信号量可用于提供对当前计算机上资源的独占访问,或限制可同时使用资源的进程数。
2、共享内存可用于提供对全局变量的访问。不同的 httpd 守护程序甚至其他程序(例如 Python、C 等)都能够访问这些数据以提供全局数据交换。共享内存对于多进程同时访问是不安全的。需要使用信号量进行同步。
3、消息传递功能可以用于向其他进程发送消息或从其他进程接收消息。它们提供了一种在进程之间交换数据的简单有效的方法,而无需使用Unix域套接字建立替代方案;
Windows平台上只有共享内存函数和ftok()可用。既不支持信号量也不支持进程间消息传递功能。
默认不启用
--enable-sysvsem编译启用System V信号量
--enable-sysvshm编译启用System V共享内存,windows需要配置加载php_sysvshm.dll
--enable-sysvmsg编译启用System V消息
// 将可访问文件$filename和项目标识符字符串$project_id(a-z)转换为System V IPC密钥,成功时返回int值,失败返回-1
ftok($filename, $project_id);
// 其他函数中的$key可以使用此函数来创建
消息队列
// 检查队列$key(int类型)是否存在
msg_queue_exists($key);
// 创建或附加到消息队列$key(int类型),返回用于访问System V消息队列key的SysvMessageQueue实例;$permissions为队列权限,消息队列存在时将被忽略
$sysvMessageQueue = msg_get_queue($key, $permissions = 0666);
// 向队列$sysvMessageQueue发送$message_type(必须大于0)(int类型参数)类型的消息$message(类型不限)
// $serialize为true时将对消息进行序列化,$message_typ类型必须为string,int,float或bool
// $blocking为true时如果消息太大无法放入队列,则脚本进行阻塞等待,直到队列能容下此消息,为false时消息过大将产生错误并将$error_code的参数赋值为错误码MSG_EAGAIN
// $error_code为函数失败时的错误码
msg_send($sysvMessageQueue, $message_type, $message, $serialize = true, $blocking = true, $error_code);
$flags = [
MSG_IPC_NOWAIT, // 未接收到消息时不阻塞直接返回,并将错误码MSG_ENOMSG赋值给$error_code
MSG_EXCEPT, // 与大于0的$desired_message_type结合使用,接收不等于$desired_message_type的第一条消息
MSG_NOERROR, // 截断超过$max_message_size字节大小的消息
];
// 从指定队列$sysvMessageQueue获取$desired_message_type类型的消息,接收消息的类型存储在$received_message_type中,消息内容存储在$message中,消息大小超过$max_message_size字节时函数将失败
// $desired_message_type为0时返回队列前面的消息,大于0时返回该类型的第一条消息,小于0时读取队列中类型小于或等于绝对值的第一条消息,如果没有消息则阻塞等待直到获取到消息
// $unserialize为true将接收到的消息进行反序列化,为false消息将以二进制安全字符串的形式返回
// $error_code为函数失败时的错误码
msg_receive($sysvMessageQueue, $desired_message_type, $received_message_type, $max_message_size, $message, $unserialize = true, $flag = true, $error_code);
// 修改消息队列$sysvMessageQueue的基础队列数据结构$data;修改于创建者应是同一身份
$data = [
'msg_perm.uid' => '',
'msg_perm.gid' => '',
'msg_perm.mode' => '',
'msg_qbytes' => '' // root特权才能修改
];
msg_set_queue($sysvMessageQueue, $data);
// 获取消息队列$sysvMessageQueue的元数据数组
msg_stat_queue($sysvMessageQueue);
[
'msg_perm.uid', // 队列所有者的uid。
'msg_perm.gid', // 队列所有者的gid。
'msg_perm.mode', // 队列的文件访问模式。
'msg_stime', // 最后一条消息被发送到队列的时间。
'msg_rtime', // 从队列接收到最后一条消息的时间。
'msg_ctime', // 队列最后一次更改的时间。
'msg_qnum', // 等待从队列中读取的消息数量。
'msg_qbytes', // 一个消息队列中允许的最大字节数。在Linux上,这个值可以通过/proc/sys/kernel/msgmnb.读取和修改
'msg_lspid', // 向队列发送最后一条消息的进程的pid。
'msg_lrpid', // 从队列接收到最后一条消息的进程的pid。
];
// 销毁队列$sysvMessageQueue并释放资源
msg_remove_queue($sysvMessageQueue);
信号量
// 获取System V信号量$key(int类型)的信号量标识符SysvSemaphore,key为0时,sem_get()将创建一个新的专用信号量
// 信号量可同时被$max_acquire个进程获取
// $permissions为信号权限,仅当进程发现它是当前附加到信号量的唯一进程时,才设置此值
// $auto_release指定是否应在请求关闭时自动释放信号灯
$sysvSemaphore = sem_get($key, $max_acquire = 1, $permissions = 0666, $auto_release = true);
// 获取信号量$sysvSemaphore,如果获取信号量将导致超过其最大信号量,那么这个进程将永远被阻塞;在处理一个请求之后,任何进程获得的但没有显式释放的信号量都会被自动释放,并生成一个警告
// $non_blocking为true时获取不到时将阻塞等待直到获取到位置,为false时获取不到将立即返回
sem_acquire($sysvSemaphore, $non_blocking = false);
// 释放信号量$sysvSemaphore,如果当前正在被进程调用获取将发生警告
sem_release($sysvSemaphore);
// 删除信号量$sysvSemaphore,删除后将无法访问
sem_remove($sysvSemaphore);
共享内存段
// 创建或打开一个$size大小的共享内存段$key(int类型),返回System V共享内存的SysvSharedMemory实例
// 第二次调用时$size和$permissions将被忽略
// $size默认为php.ini中的sysvshm.init_mem配置的值(默认10000字节)
$sysvSharedMemory = shm_attach($key, $size = null, $permissions = 0666);
// 检查共享内存$sysvSharedMemory中是否存在指定变量$key
shm_has_var($sysvSharedMemory, $key);
// 在共享内存$sysvSharedMemory中插入或更新变量$key(int类型),$key的值为$value
shm_put_var($sysvSharedMemory, $key, $value);
// 获取共享内存$sysvSharedMemory中变量$key(int类型)的值,获取后值不会删除
shm_get_var($sysvSharedMemory, $key);
// 删除共享内存$sysvSharedMemory中的变量$key(int类型)并释放占用的内存
shm_remove_var($sysvSharedMemory, $key);
// 断开共享内存$sysvSharedMemory;共享内存在Unix系统中仍然存在,并且数据仍然存在。
shm_detach($sysvSharedMemory);
// 删除共享内存$sysvSharedMemory;所有数据将被销毁
shm_remove($sysvSharedMemory);