我们在上一节里面说到了需要使用epoll来实现协程的调度,实际上epoll也可以实现我们的sleep功能,我们现在来实现一下。首先,我们需要一个全局的epoll,我把我们今后会用到的全局变量保存在统一的一个结构体里面。我们在文件study.h里面定义这个结构体:
typedef struct
{
stPoll_t poll;
} stGlobal_t;目前,里面存放了stPoll_t结构体,这个结构体我们也在study.h里面进行定义:
typedef struct
{
int epollfd;
int ncap;
struct epoll_event *events;
} stPoll_t;因为我们使用了epoll_event,所以,我们需要在study.h里面引入头文件:
#include <sys/epoll.h>其中,
epollfd用来保存我们创建的那个epollfd。
events是用来保存epoll返回的事件。
ncap是events数组的大小。
然后,我们新建一个文件src/core/base.cc,文件内容如下:
#include "study.h"
stGlobal_t StudyG;然后,我们需要在文件study.h里面去声明这个变量在其他地方定义了:
extern stGlobal_t StudyG;为什么我们不直接在文件study.h里面定义全局变量StudyG呢?因为,如果我们在文件study.h里面定义了这个全局的变量,那么,如果头文件study.h被多个地方引入了,那么,编译器就会认为这个全局变量重复定义了,所以,我们需要在一个地方去定义它,然后在另一个地方声明这是一个外部变量。
因为我们增加了一个需要被编译到的源文件,所以我们需要修改我们的config.m4文件:
study_source_file="\
study.cc \
study_coroutine.cc \
study_coroutine_util.cc \
src/coroutine/coroutine.cc \
src/coroutine/context.cc \
${STUDY_ASM_DIR}make_${STUDY_CONTEXT_ASM_FILE} \
${STUDY_ASM_DIR}jump_${STUDY_CONTEXT_ASM_FILE} \
study_server_coro.cc \
src/socket.cc \
src/log.cc \
src/error.cc \
src/core/base.cc
"然后,我们需要去修改我们的调度器代码:
int PHPCoroutine::scheduler()
{
int timeout;
size_t size;
uv_loop_t *loop = uv_default_loop();
StudyG.poll.epollfd = epoll_create(256);
StudyG.poll.ncap = 16;
size = sizeof(struct epoll_event) * StudyG.poll.ncap;
StudyG.poll.events = (struct epoll_event *) malloc(size);
memset(StudyG.poll.events, 0, size);
while (loop->stop_flag == 0)
{
timeout = uv__next_timeout(loop);
epoll_wait(StudyG.poll.epollfd, StudyG.poll.events, StudyG.poll.ncap, timeout);
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
uv__run_timers(loop);
if (uv__next_timeout(loop) < 0)
{
uv_stop(loop);
}
}
return 0;
}代码很简单,主要过程如下:
1、创建一个epollfd,然后保存在全局变量
2、在堆中为全局的StudyG.poll.events分配内存,默认的大小是16
3、把usleep替换为epoll_wait,时间是timeout
然后,我们需要重新生成一下我们的Makefile:
~/codeDir/cppCode/study # phpize --clean && phpize && ./configure然后编译、安装扩展:
~/codeDir/cppCode/study # make && make install编写测试代码:
<?php
Sgo(function ()
{
var_dump("here1");
Sco::sleep(0.5);
var_dump("here2");
Sco::sleep(1);
var_dump("here3");
Sco::sleep(1.5);
var_dump("here4");
Sco::sleep(2);
var_dump("here5");
});
Sco::scheduler();执行脚本:
~/codeDir/cppCode/study # php test.php
string(5) "here1"
string(5) "here2"
string(5) "here3"
string(5) "here4"
string(5) "here5"
~/codeDir/cppCode/study # 符合预期。