1.什么是协程?
协程是一个“轻量级线程”,更倾向解释为一个特殊的函数。
2.为什么要用协程?
在同步的编程方式,逻辑清晰易于编写,然而性能的却不如,异步的编程方式,异步的编程方式,逻辑不够清晰,性能较高。为了结合两者的优点:实现同步的编程方式异步的性能,由此协程就应运而生。
3.setjmp/longjmp实现函数的切换代码
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
void func(int arg)
{
printf("func: %d\n",arg);
longjmp(env,++arg);
}
int main()
{
int ret=setjmp(env);
if(0==ret){
func(ret);
}else if(1==ret){
func(ret);
}else if(2==ret){
func(ret);
}
return 0;
}
4.hook的代码
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <ucontext.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#define HOOK 1
#if HOOK
typedef ssize_t (*read_t)(int fd ,void*buf,size_t count);
read_t read_f=NULL;
typedef ssize_t (*write_t)(int fd ,void*buf,size_t count);
write_t write_f=NULL;
ssize_t read(int fd,void *buf,size_t count){
struct pollfd fds[1]={0};
fds[0].fd=fd;
fds[0].events=POLLIN;
int res=poll(fds,1,0);
if(res<=0){//事件尚未就绪?
// fd --> epoll_ctl();
//swapcontext();
}
ssize_t ret=read_f(fd,buf,count);
printf("read:%s \n",( char *)buf);
return ret;
}
ssize_t writre(int fd,void *buf,size_t count){
printf("write: %s\n", ( char *)buf);
return write_f(fd, buf, count);
}
void init_hook(void){
if(!read_f){
read_f=dlsym(RTLD_NEXT,"read");
}
if(!write_f){
write_f=dlsym(RTLD_NEXT,"write");
}
}
#endif
int main()
{
init_hook();
int socketfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=htons(INADDR_ANY);
serveraddr.sin_port=htons(2048);
if(-1==bind(socketfd,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr)))
{
perror("bind error:");
return -1;
}
listen(socketfd,10);
struct sockaddr_in clientaddr;
socklen_t len=sizeof(clientaddr);
int clientfd =accept(socketfd,(struct sockaddr*)&clientaddr,&len);
printf("accept");
while(1)
{
char buffer[128]={0};
int count =read(clientfd,buffer,128);
if(0==count )
{
break;
}
write(clientfd,buffer,count);
printf("sockfd: %d, clientfd: %d, count: %d, buffer: %s\n", socketfd, clientfd, count, buffer);
}
return 0;
}
5.ucontext代码实现
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <ucontext.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
ucontext_t ctx[3];
ucontext_t main_ctx;
int count=0;
typedef ssize_t (*read_t)(int fd, void *buf, size_t count);
read_t read_f = NULL;
typedef ssize_t (*write_t)(int fd, const void *buf, size_t count);
write_t write_f = NULL;
ssize_t read(int fd, void *buf, size_t count) {
ssize_t ret = read_f(fd, buf, count);
printf("read: %s\n", (char *)buf);
return ret;
}
ssize_t write(int fd, const void *buf, size_t count) {
printf("write: %s\n", (const char *)buf);
return write_f(fd, buf, count);
}
void init_hook() {
if (!read_f) {
read_f = dlsym(RTLD_NEXT, "read");
}
if (!write_f) {
write_f = dlsym(RTLD_NEXT, "write");
}
}
//coroutine 1
void func1(void){
while(count++<30){
printf("1\n");
swapcontext(&ctx[0],&main_ctx);
printf("4\n");
}
}
//coroutine 2
void func2(void){
while(count++<30){
printf("2\n");
swapcontext(&ctx[1],&main_ctx);
printf("5\n");
}
}
//coroutine 3
void func3(void){
while(count++<30){
printf("3\n");
swapcontext(&ctx[2],&main_ctx);
printf("6\n");
}
}
int main(){
init_hook();
int fd =open("a.txt",O_CREAT|O_RDWR);
if(fd<0){
return -1;
}
char *str="Hello ,LuGaoyang!";
write(fd,str,strlen(str));
char buff[128]={0};
read(fd,buff,128);
printf("buffer :%s",buff);
#if 1
char stack1[2048]={0};
char stack2[2048]={0};
char stack3[2048]={0};
getcontext(&ctx[0]);
ctx[0].uc_stack.ss_sp=stack1;
ctx[0].uc_stack.ss_size=sizeof(stack1);
ctx[0].uc_link=&main_ctx;
makecontext(&ctx[0],func1,0);
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp=stack2;
ctx[1].uc_link=&main_ctx;
ctx[1].uc_stack.ss_size=sizeof(stack2);
makecontext(&ctx[1],func2,0);
getcontext(&ctx[2]);
ctx[2].uc_stack.ss_sp=stack3;
ctx[2].uc_stack.ss_size=sizeof(stack3);
ctx[2].uc_link=&main_ctx;
makecontext(&ctx[2],func3,0);
printf("swapcontext\n");
//int i = 30;
while (count <= 30) { // scheduler
swapcontext(&main_ctx, &ctx[count%3]);
}
printf("\n");
#endif
}
6.协程的代码
关于协程的代码具体实现见下链接:
https://github.com/wangbojing/NtyCohttps://github.com/wangbojing/NtyCo