swoole_process创建的进程默认在父子进程间通过管道的方式进行进程间通信方式,而swoole_process也提供消息队列的方式进行进程间通信,对外和队列相关的接口有创建队列、push消息、pop消息、stat消息、销毁队列等,我们下面逐步分析。
启用队列的操作如下:
bool swoole_process->useQueue(int $msgkey = 0, int $mode = 2);
下面我们逐步分析下其流程。
static PHP_METHOD(swoole_process, useQueue)
{
long msgkey = 0;
long mode = 2;
//解析输入参数
//msgkey表示消息队列的key,默认会使用ftok(__FILE__, 1)作为KEY
//通信模式,默认为2,表示争抢模式,所有创建的子进程都会从队列中取数据
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &msgkey, &mode) == FAILURE)
{
RETURN_FALSE;
}
//获取swoole内部封装对象
swWorker *process = swoole_get_object(getThis());
if (msgkey <= 0)//未传入msgkey信息
{
msgkey = ftok(sw_zend_get_executed_filename(), 1);//通过当前文件作为参数调用ftok生成msgkey
}
swMsgQueue *queue = emalloc(sizeof(swMsgQueue));//申请队列空间
if (swMsgQueue_create(queue, 1, msgkey, 0) < 0)//创建队列,后续展开分析
{
RETURN_FALSE;
}
if (mode & MSGQUEUE_NOWAIT)//设置队列非阻塞属性
{
swMsgQueue_set_blocking(queue, 0);
mode = mode & (~MSGQUEUE_NOWAIT);
}
process->queue = queue;
process->ipc_mode = mode;
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("msgQueueId"), queue->msg_id TSRMLS_CC);//更新soole_process的msgQueueId属性
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("msgQueueKey"), msgkey TSRMLS_CC);//更新soole_process的msgQueueKey属性
RETURN_TRUE;
}
int swMsgQueue_create(swMsgQueue *q, int blocking, key_t msg_key, int perms)
{
if (perms <= 0 || perms >= 01000)
{
perms = 0666;
}
int msg_id;
msg_id = msgget(msg_key, IPC_CREAT | perms);//调用linux系统调用msgget创建队列,返回队列ID
if (msg_id < 0)//创建失败
{
swSysError("msgget() failed.");
return SW_ERR;
}
else//成功
{
bzero(q, sizeof(swMsgQueue));
q->msg_id = msg_id;
q->perms = perms;
q->blocking = blocking;
swMsgQueue_set_blocking(q, blocking);
}
return 0;
}