一百行代码实现协程demo

博客传送门:libco源码分析、学习笔记(腾讯协程开源库) x86_64部分 

协程基本原理就是上下文和栈的切换,本篇将libco中核心代码抽离出来实现一个迷你的协程实现演示。

一、Linux下效果展示

在deepin (64位 Linux)和mac os上测试成功了。贴一下效果图:

deepin(64位)效果图:

macOs(64位)效果图:

红色部分为并发部分。

二、代码

新建一个coctx_swap.S汇编文件,代码如下:

代码来源于libco  (注意:libco此上下文切换汇编代码有bug,详情参考GitHub的libco项目)

.globl coctx_swap
#if !defined( __APPLE__ ) && !defined( __FreeBSD__ )
.type  coctx_swap, @function
#endif
coctx_swap:
	leaq 8(%rsp),%rax
	leaq 112(%rdi),%rsp
	pushq %rax
	pushq %rbx
	pushq %rcx
	pushq %rdx

	pushq -8(%rax) //ret func addr

	pushq %rsi
	pushq %rdi
	pushq %rbp
	pushq %r8
	pushq %r9
	pushq %r12
	pushq %r13
	pushq %r14
	pushq %r15
	
	movq %rsi, %rsp
	popq %r15
	popq %r14
	popq %r13
	popq %r12
	popq %r9
	popq %r8
	popq %rbp
	popq %rdi
	popq %rsi
	popq %rax //ret func addr
	popq %rdx
	popq %rcx
	popq %rbx
	popq %rsp
	pushq %rax
	
	xorl %eax, %eax
	ret

此汇编的作用是上下文切换。

新建一个coctx.c

#include "coctx.h"
#include <string.h>

#define RSP 0
#define RIP 1
#define RBX 2
#define RDI 3
#define RSI 4

#define RBP 5
#define R12 6
#define R13 7
#define R14 8
#define R15 9
#define RDX 10
#define RCX 11
#define R8 12
#define R9 13
//-------------
// 64 bit
//low | regs[0]: r15 |
//    | regs[1]: r14 |
//    | regs[2]: r13 |
//    | regs[3]: r12 |
//    | regs[4]: r9  |
//    | regs[5]: r8  |
//    | regs[6]: rbp |
//    | regs[7]: rdi |
//    | regs[8]: rsi |
//    | regs[9]: ret |  //ret func addr
//    | regs[10]: rdx |
//    | regs[11]: rcx |
//    | regs[12]: rbx |
//hig | regs[13]: rsp |
enum
{
	kRDI = 7,
	kRSI = 8,
	kRETAddr = 9,
	kRSP = 13,
};
//64 bit
extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap");

int coctx_make( coctx_t *ctx,coctx_pfn_t pfn)
{
	char *sp = ctx->ss_sp + ctx->ss_size;
	sp = (char*) ((unsigned long)sp & -16LL  );
	memset(ctx->regs, 0, sizeof(ctx->regs));
	ctx->regs[ kRSP ] = sp - 8;
	ctx->regs[ kRETAddr] = (char*)pfn;
	return 0;
}
int coctx_init( coctx_t *ctx )
{
	memset( ctx,0,sizeof(*ctx));
	return 0;
}

新建一个coctx.h

#include <stdlib.h>
typedef void* (*coctx_pfn_t)( void* s, void* s2 );
struct coctx_t
{
	void *regs[ 14 ];
	size_t ss_size;
	char *ss_sp;
};
typedef struct coctx_t coctx_t;

int coctx_init( coctx_t *ctx );
int coctx_make( coctx_t *ctx,coctx_pfn_t pfn);

到此为止短小精悍的协程库已经建立完毕了 

三、使用

建立main.c

#include<stdio.h>
#include"coctx.h"
extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap");
coctx_t ctx_func,ctx_main;
int i=0;
void *func(void*arga,void*argb){
    while(1){
        printf("hello \n");
        i++;
        coctx_swap(&ctx_func,&ctx_main);//swap context
    }
}
int main(){
    printf("start\n");

    coctx_init(&ctx_main);
    coctx_init(&ctx_func);
    //alloc stack memory
    ctx_func.ss_sp=malloc(128);
    ctx_func.ss_size=128;

    //init func coroutine
    coctx_make( &ctx_func,func);//struct ctx, main function

    printf("make\n");
    while(1){
        printf("nihao \n");
        i++;
        if(i>=5)
            return 0;
        coctx_swap(&ctx_main,&ctx_func); //swap context
    }
}

其中func函数和main函数中两个循环交替运行,预期结果是打印一个nihao,再打印一个hello,再打印nihao。。。在没有操作系统强参与下实现了并发。

使用下列命令编译运行:

gcc -o run main.c coctx.c coctx_swap.S
./run

以下是一个使用协程风格实现的简单的 Socket Demo,其中包括收发消息的功能。这个 Demo 使用 Python 的 asyncio 模块实现协程。 ```python import asyncio async def handle_client(reader, writer): while True: data = await reader.read(1024) if not data: break message = data.decode().strip() print(f"Received message: {message}") response = f"You said: {message}" writer.write(response.encode()) await writer.drain() writer.close() async def main(): server = await asyncio.start_server(handle_client, '127.0.0.1', 8888) async with server: await server.serve_forever() asyncio.run(main()) ``` 在这个 Demo 中,我们使用 asyncio.start_server() 函数创建了一个服务器,监听本地的 8888 端口。当有客户端连接时,handle_client() 协程会被调用来处理连接。 在 handle_client() 函数中,我们首先读取客户端发送的数据,然后将其打印出来。接着,我们构建了一个简单的响应消息,并将其发送回客户端。最后,我们关闭了连接。 在 main() 函数中,我们使用 asyncio.run() 来运整个程序。这个函数会自动创建一个新的事件循环,并运其中的协程。 现在,我们可以使用 telnet 或其他工具来连接到这个服务器,并发送消息。例如: ``` $ telnet 127.0.0.1 8888 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello, server! You said: Hello, server! ``` 上面的例子只是一个简单的演示。在实际应用中,我们可能需要更复杂的逻辑来处理数据、连接管理等等。但是,协程风格的代码可以让这些逻辑更加清晰和易于维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值