您现在的位置是:
网站首页
> 程序设计 
> Linux 
协成实现之ucontext簇函数
简介在协程的时候需要在用户程序中实现调度切换,多数人认为要实现切换可能需要嵌入汇编实现,其实不然。在Linux中还有两组系统调用可以实现切换,那就是是setjmp/longjmp和ucontext簇函数
ucontext_t定义
在5.4的内核中,ucontext_t
的定义如下:
typedef struct ucontext_t
{
unsigned long int __ctx(uc_flags);
struct ucontext_t *uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
sigset_t uc_sigmask;
struct _libc_fpstate __fpregs_mem;
} ucontext_t;
在所有字段中,我们只关心uc_link
和uc_stack
两个参数。
uc_link
指的是当前上下文结束后需要执行的上下文,如果设为NULL,则表示当前结束后进程退出。
uc_stack
中需要指定协成的栈地址和大小。
getcontext
int getcontext(ucontext_t *ucp);
该函数用来获取当前上下文保存到ucp结构中
makecontext
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
该函数用来修改上下文信息,可以用来设置上下文的入口函数,其中ucp必须先经过getcontext
初始化。
setcontext
int setcontext(const ucontext_t *ucp)
该函数是将上下文恢复到CPU中并执行,ucp上下文是由getconext
和makecontext
设置而来。
swapcontext
int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
该函数用来切换上下文,同时保存当前上下问到oucp,ucp上下文是由getconext
和makecontext
设置而来。
例1、用getcontext/setcontext实现for循环
#include <ucontext.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int idx = 0;
ucontext_t ctx1;
getcontext(&ctx1);
printf("%d\n", idx);
idx++;
sleep(1);
setcontext(&ctx1);
return 0;
}
./01
0
1
2
.
.
.
例2、用makecontext/(setcontext/swapcontext)实现函数调用
#include <ucontext.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void fun() {
printf("this is fun...\n");
}
int main() {
ucontext_t ctx1;
getcontext(&ctx1);
ctx1.uc_stack.ss_sp = malloc(4096);
ctx1.uc_stack.ss_size = 4096;
ctx1.uc_link = nullptr;
makecontext(&ctx1, fun, 0);
//setcontext(&ctx1);
ucontext_t ctx2;
swapcontext(&ctx2, &ctx1);
return 0;
}
输出:
./02
this is fun...
例3、ucontext簇函数实现函数循环调用
#include <ucontext.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
ucontext_t fun_ctx, test_ctx;
void test();
void fun() {
printf("this is %s...\n", __FUNCTION__);
sleep(1);
setcontext(&test_ctx);
}
void test() {
printf("this is %s...\n", __FUNCTION__);
sleep(1);
setcontext(&fun_ctx);
}
int main() {
getcontext(&test_ctx);
getcontext(&fun_ctx);
test_ctx.uc_stack.ss_sp = malloc(4096);
test_ctx.uc_stack.ss_size = 4096;
test_ctx.uc_link = &fun_ctx;
makecontext(&test_ctx, test, 0);
fun_ctx.uc_stack.ss_sp = malloc(4096);
fun_ctx.uc_stack.ss_size = 4096;
fun_ctx.uc_link = &test_ctx;
makecontext(&fun_ctx, fun, 0);
test();
return 0;
}
./03
this is test...
this is fun...
this is test...
this is fun...
this is test...
上一篇: MD5、对称加密、非对称加密
下一篇: MySQL索引面试题