使用makecontext实现用户线程

Mac上MySQL出现secure-file-priv为null 在使用MySQL导入导出文件时出现了错误,原因是没有配置secure-file-priv。 我的MySQL版本是8.0.13,使用如下命令查看secure-file-priv。 结果发现secure-file-priv为空,此时需要为它配置一个文件夹。 解决方案: 1)到MySQL的安装目录中去,Mac中是的是 /usr/local/mysql/support-files,该目录下有一... 阅读详情
使用makecontext实现用户线程

       现代Unix系统都在ucontext.h中提供用于上下文切换的函数,这些函数有getcontext, setcontext,swapcontext 和makecontext。其中,getcontext用于保存当前上下文,setcontext用于切换上下文,swapcontext会保存当前上下文并切换到另一个上下文,makecontext创建一个新的上下文。实现用户线程的过程是:我们首先调用getcontext获得当前上下文,然后修改ucontext_t指定新的上下文。同样的,我们需要开辟栈空间,但是这次实现的线程库要涉及栈生长的方向。然后我们调用makecontext切换上下文,并指定用户线程中要执行的函数。
       在这种实现中还有一个挑战,即一个线程必须可以主动让出CPU给其它线程。swapcontext函数可以完成这个任务,图4展示了一个这种实现的样例程序,child线程和parent线程不断切换以达到多线程的效果。在libfiber-uc.c文件中可以看到完整的实现。

#include 
#include 
#include 

// 64kB stack
#define FIBER_STACK 1024*64

ucontext_t child, parent;

// The child thread will execute this function
void threadFunction()
{
printf( "Child fiber yielding to parent" );
swapcontext( &child, &parent );
printf( "Child thread exiting\n" );
swapcontext( &child, &parent );
}

int main()
{
// Get the current execution context
getcontext( &child );

// Modify the context to a new stack
child.uc_link = 0;
child.uc_stack.ss_sp = malloc( FIBER_STACK );
child.uc_stack.ss_size = FIBER_STACK;
child.uc_stack.ss_flags = 0; 
if ( child.uc_stack.ss_sp == 0 )
{
perror( "malloc: Could not allocate stack" );
exit( 1 );
}

// Create the new context
printf( "Creating child fiber\n" );
makecontext( &child, &threadFunction, 0 );

// Execute the child context
printf( "Switching to child fiber\n" );
swapcontext( &parent, &child );
printf( "Switching to child fiber again\n" );
swapcontext( &parent, &child );

// Free the stack
free( child.uc_stack.ss_sp );

printf( "Child fiber returned and stack freed\n" );

return 0;
}
图4用makecontext实现线程


用户级线程的抢占

       抢占实现的一个最重要的因素就是定时触发的计时器中断,它的存在使得我们能够中断当前程序的执行,异步对进程的时间片消耗情况进行统计,并在必要的时候(可能是时间片耗尽,也可能是一个高优先级的程序就绪)从当前进程调度到其它进程去执行。

       对于用户空间程序来说,与内核空间的中断相对应的就是信号,它和中断一样都是异步触发,并能引起执行流的跳转。所以要想实现用户级线程的抢占,我们可以借助定时器信号(SIGALRM),必要时在信号处理程序内部进行上下文的切换。

       为了验证自己的想法,我在上篇文章提到的协同多线程的基础上加上了相关抢占代码,具体实现如下:

#include <stdlib.h>
#include <stdio.h>
#include <ucontext.h>
#include <sys/time.h>

#define STACK_SIZE 4096
#define UTHREAD_MAX_NUM 256
#define INIT_TICKS 10

typedef int uthread_t;
typedef void uthread_attr_t;
uthread_t current = 0;

#define uthread_self() current

struct uthread_struct
{
        int used;
        ucontext_t context;
        char stack[STACK_SIZE];
        void* (*func)(void *arg);
        void *arg;
        void *exit_status;
        int ticks;
};

static struct uthread_struct uthread_slots[UTHREAD_MAX_NUM];

void panic(void)
{
                fprintf(stderr, "Panic, bala bala...\n");
                exit(EXIT_FAILURE);
}

void idle_thread(void)
{
        int i;

        for (i = 1; i < UTHREAD_MAX_NUM; i ++)
                if (uthread_slots[i].used)
                        break;

        if (i == UTHREAD_MAX_NUM)
                panic();
        if (current != 0)
                uthread_slots[current].used = 0;
        current = i;
        swapcontext(&uthread_slots[0].context,&uthread_slots[current].context);
}

void uthread_context_init(int tid)
{
        getcontext(&uthread_slots[tid].context);
        uthread_slots[tid].context.uc_stack.ss_sp = uthread_slots[tid].stack;
        uthread_slots[tid].context.uc_stack.ss_size =sizeof(uthread_slots[tid].stack);
        uthread_slots[tid].context.uc_link = &uthread_slots[0].context;
}

void uthread_init(void)
{
        uthread_context_init(0);
        uthread_slots[0].used = 1;
        makecontext(&uthread_slots[0].context, idle_thread, 0);
}

void uthread_schedule(void);

void uthread_exit(void *exit_status)
{
        uthread_slots[current].exit_status = exit_status;
        uthread_slots[current].used = 0;
        uthread_schedule();
}

void uthread_helper(void)
{
        uthread_exit(uthread_slots[current].func(uthread_slots[current].arg));
}

int uthread_create(uthread_t *thread, const uthread_attr_t *attr,
                        void* (*start_routine)(void*), void *arg)
{
        static int last_used = 0;
        int i;

        for (i = (last_used + 1) % UTHREAD_MAX_NUM; i != last_used;
                        i = (i + 1) % UTHREAD_MAX_NUM)
                if (!uthread_slots[i].used)
                        break;
        if (i == last_used)
                return -1;
        last_used = i;

        if (thread != NULL)
                *thread = i;
        uthread_context_init(i);
        uthread_slots[i].used = 1;
        uthread_slots[i].func = start_routine;
        uthread_slots[i].arg = arg;
        uthread_slots[i].exit_status = 0;
        uthread_slots[i].ticks = uthread_slots[current].ticks / 2;
        uthread_slots[current].ticks -= uthread_slots[i].ticks;
        makecontext(&uthread_slots[i].context, uthread_helper, 0);

        return 0;
}

void uthread_schedule(void)
{
        int i, prev;

        for (i = (current + 1) % UTHREAD_MAX_NUM; i != current;
                        i = (i + 1) % UTHREAD_MAX_NUM)
                if (uthread_slots[i].used)
                        break;
        if (i == current)
                panic();

        prev = current;
        current = i;
        swapcontext(&uthread_slots[prev].context,&uthread_slots[current].context);
}

void* thread(void *arg)
{
        int i;

        for (i = 0; 1; i ++) {
                if (i % 1000 == 0)
                        printf("thread/%d(%s): i = %d\n", current, (char*)arg,i);
                uthread_create(NULL, NULL, thread, arg);
                if (i % 1000000 == 0)
                uthread_schedule();
        }
}

void sig_ticks_timer(int signo)
{
        if (--uthread_slots[current].ticks <= 0) {
                uthread_slots[current].ticks = INIT_TICKS;
                uthread_schedule();
        }
}

int main(int argc, char *argv[])
{
        uthread_t tid;
        struct itimerval ticks_timer;

        uthread_init();

        uthread_create(&tid, NULL, thread, "hw1");
        printf("tid is %d\n", tid);
        uthread_create(&tid, NULL, thread, "hw2");
        printf("tid is %d\n", tid);

        signal(SIGALRM, sig_ticks_timer);
        ticks_timer.it_interval.tv_sec = 0;
        ticks_timer.it_interval.tv_usec = 10000;
        ticks_timer.it_value.tv_sec = 0;
        ticks_timer.it_value.tv_usec = 10000;
        setitimer(ITIMER_REAL, &ticks_timer, NULL);

        while (1)
                idle_thread();

        return 0;
}

       似乎该有的都有了,也许真的可以在用户空间实现一个虚拟的操作系统环境玩呢...

GhidraMCP:AI驱动的逆向工程革命——让LLM自主操作Ghidra进行自动化分析 (Ghidra Machine Control Protocol)应运而生,它通过将LLM与Ghidra(美国NSA开源逆向工具)结合,实现了AI驱动的自动化逆向工程流程。逆向工程是软件安全、漏洞分析和代码审计的核心环节,但传统方法依赖人工分析,耗时且易出错。未来,随着LLM技术的演进和逆向工程工具的优化,GhidraMCP有望成为安全研究人员和开发者的核心工具,推动逆向工程进入“AI辅助时代”。GhidraMCP通过LLM与Ghidra的深度整合,重新定义了逆向工程的自动化边界。 阅读详情

相关推荐

RC滤波电路工作原理:【带图+公式计算】

容抗Xc和电容C成反比,和频率f也成反比,C越大,交流电容易通过电容,说明电容量大,电容的阻碍作用小;交流电的频率高,交流电也容易通过电容,说明频率高,电容的阻碍作用也小。我们可以看到,一个2V的纹波,经常RC电路后,幅值下降到mv级别,基本可以忽略不计,这就是RC滤波电路的工作原理。一个频率为1Khz的信号,通过一个容值为0.1uf的电容,计算电容对该信号产生的阻抗。将RC滤波器电路中的电阻,取值为1KΩ,电容取值为0.47uf,纹波幅值为2V。从公式1可以看到,Xc越大,Vout值就越接近Vin的值。

weixin_66299220的博客 2万+

linux ucontext族函数的原理及使用

ucontext函数族 这里的context族是偏向底层的,其实底层就是通过汇编来实现的,但是我们使用的时候就和平常使用变量和函数一样使用就行,因为大佬们已经将它们封装成C库里了的 我们先来看看寄存器寄存器:寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果 我们常用的寄存器是X86-64中的其中16个64位的寄存器,它们分别是 %rax, %rbx, %rcx, %rdx, %esi, %edi, %rbp, %rsp %r8, %r9, %r10, %r11, %

chenzhjlf的专栏 1891

OpenCV透视变换实战:5分钟搞定歪斜证件照矫正(附完整代码)

本文详细介绍了如何使用OpenCV的透视变换技术快速矫正歪斜证件照,包含完整的Python代码实现。通过特征检测、坐标计算和矩阵变换三个核心步骤,5分钟内即可将手机拍摄的歪斜图像自动矫正为专业级证件照,大幅提升图像处理效率。

weixin_29094979的博客 481

Linux C语言实现协程功能

协程,作为go语言的亮点,可以实现用户在用户层面根据业务实际情况来实现进程切换。但是由于C语言才是运行速度最快的语言,并且在很多时候,比如mips架构等,均只支持C语言,因此C语言实现协程功能对于开发人员来说是完全必要的功能。下面小沃就来教教大家在C语言环境下如何实现协程功能。这里主要用到了3个函数:getcontext,makecontext,swapcontext,这三个函数的功能分别是:getcontext:初始化上下文makecontext:创建协程与其要调用的函数swapcontext:切换到协程

zz460833359的博客 1450

在 CentOS7 下安装 Cadence IC验证平台 INCISIVE152

前言 本文所使用的软件 虚拟机软件:VMware Workstation 15 PRO 如何安装? 操作系统:CentOS-7, CentOS-7-x86_64-DVD-1810.iso 如何安装? 简介 INCISIVE Incisive是nc_verilog, nc_sim, nc_lauch,以及ABV,TBV的集合,用于仿真和验证。 InstallScape InstallSc...

沈醉不知的博客 2万+

《科研伦理与学术规范》 全部 习题_答案 2020年秋

科研伦理与学术规范 答案 文章目录科研伦理与学术规范 答案1. 第一章课后习题(必做) 答案1.1 第一章Demo2. 第二章课后习题(必做) 答案3. 第三章课后习题(必做) 答案4. 第四章课后习题(必做) 答案5. 第五章课后习题(必做) 答案6. 第六章课后习题(必做) 答案 # 每行5题 #写于2020.11.17 侵删 1. 第一章课后习题(必做) 答案 ABC, A, B ,D ,ABCD ABC, D, A, BCD, C D, D, 1.1 第一章Demo

羊老羊 25万+

C++ 利用linux函数makecontext等实现简单协程

我是一个编程新手,最近了解到协程这个概念,协程可以理解为用户级线程,在用户空间实现调度,在处理异步IO时,可以在子程序中让出cpu交给其他协程,等事件完成再切换到子程序中。当然回调也可以实现,但是使用协程会使程序“看起来”是顺序执行的。 我利用linux系统函数getcontext,makecontext,swapcontext来实现协程之间的切换。 getcontext(ucontext_t*)初始化上下文,makecontext(ucontext_t*,void(*)(void),int args)

虹少侠的博客 2023

字节跳动扣子AI应用开发平台之实战

推出背景:扣子平台由字节跳动推出,旨在让非开发者也能快速创建、调试和优化聊天机器人。上线时间:扣子平台于2024年2月1日正式上线。功能定位:扣子是一个AI聊天机器人和应用程序编辑开发平台,可以理解为字节跳动版的GPTs。

恩爸编程 5897

setcontext getcontext makecontext swapcontext

转自:https://blog.youkuaiyun.com/mrpre/article/details/78699865   Linux上下文切换以及协程        上下文切换,听起来虚无缥缈,什么是上下文,切换又是指的是什么?其实上下文就可以理解为一个进程所运行的相关的寄存器值,即包括sp/bp/pc等值,换句话说,一个上下文,就是包括了能够恢复进程运行所需要的所有必要的东西。所谓的切换, 那是多...

purple尘的专栏 819

D457深度相机调试记录(max96712+max9295A)

使用max96712解串器解4路D457相机。采集深度相机Depth和RGB流。

navy2015_163的博客 1266

PCIe-Orders set Blocks之symbol对齐

有序集的使用场合很多,如在链路link阶段,进入polling后,便开始有序集的发送。一个 Ordered Set Block 包含一个同步头,后跟一个有序集。多通道链路的所有 Lane 必须同时传输相同的有序集,而且有序集的第一个符号定义了有序集的类型。但在PCIE中,8GT/s及以上的速率,采用的是128b/130b编码。128-bit是想要传输的payload,实际会传输130-bit,多出来的2-bit就是sync header。Block有两种,通过Sync header区分:10b:表示data

weixin_44700185的博客 813

[C/C++]windows下实现swapcontext等函数实践

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34391445的博客 761

【雕爷学编程】Arduino动手做(75)---TTL转RS-485模块之二线制可以实现真正的多点双向通信

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来---小小的进步或是搞不掂的问题,希望能够抛砖引玉。 【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程) 实验七十五:TTL转RS-485模块 MAX485 RS485模块 MAX485 是一个8.

雕爷学编程 1万+

使用makecontext实现用户线程【转】

转自:http://blog.youkuaiyun.com/cyberlabs/article/details/6920138 使用makecontext实现用户线程 现代Unix系统都在ucontext.h中提供用于上下文切换的函数,这些函数有getcontext, setcontext,swapcontext 和makecontext。其中,getcontext用于保存当前上下文...

weixin_34138521的博客 171

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

用户态线程库

更轻量的线程  严格说来, 异步化的事件驱动方式出现的比线程模式更早, 线程的出现本身就是为了减轻复杂的状态机编程。 在一般情况下确实给我们的程序带来了便利. 当时另一方面也带来了不少麻烦  锁的应用, 需要小心死锁等问题. 另外互斥情况下的性能开销也是不可忽视的  共享数据的修改和读取很容易出现问题, 而且不好排查,即使有了valgrind 这样工具,很多问题依然是很容易出现  但另一方面, 这...

wendy_hl的博客 344

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【源码讲解】sylar服务器框架----协程模块

ucontext_t是一个结构体变量,其功能就是通过定义一个ucontext_t来保存当前上下文信息的。// 上下文结构体定义// 这个结构体是平台相关的,因为不同平台的寄存器不一样// 下面列出的是所有平台都至少会包含的4个成员// 当前上下文结束后,下一个激活的上下文对象的指针,只在当前上下文是由makecontext创建时有效// 当前上下文的信号屏蔽掩码// 当前上下文使用的栈内存空间,只在当前上下文是由makecontext创建时有效。

Dereyer的博客 661

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

C开发协程与线程的区别以及使用

应用场景(出现原因)—执行两个互不依赖的sql语句,正常应该是两个语句并行执行,但是实际应用上,执行两个sql语句大部分时间等待数据库服务器的响应,并发性并不能很好地执行,就会紧接着调用第二个参数指向的函数func,参数argc代表 func所需的参数,在调用makecontext之前你需要初始化参数ucp->uc_link,协程----用户态线程,使用变成语言自身完成,协程跑在主线程上,多对一的关系,显然协程比线程轻量。//保存的上下文的特定机器表示。初始化ucp结构体,将当前的上下文保存到ucp中。

weixin_51798819的博客 244

linux 线程抢占式,在Linux中如何为用户级线程实施抢占式调度?

使用用户级线程,在单个内核线程之上运行N个用户级线程.这与pthread相反,在pthread中,只有一个用户线程在内核线程上运行.N个用户级线程被抢先调度在单个内核线程上.但是如何做到这一点的细节是什么.我听到了一些建议,建议线程库进行设置,以便内核发送信号,这是将执行从单个用户级线程拉到信号处理程序的机制,然后可以执行抢先式调度.但是,如何保存和/或修改状态(例如寄存器和线程结构)以使其全部正...

weixin_34832150的博客 635

C语言实现协程----初探

协程定义 协程,从编程的角度看来,可以理解为用户自己能控制和调度的线程,可以理解为用户级别的线程。一个线程可以有多个协程,一个进程也可以有多个协程。 协程实现 协程的实现有多种方式 setjmp和longjmp sigsetjmp和siglongjmp ucontext函数族 本次采用ucontext实现,思路是:在进行函数跳转前,将获取当前调用者的上下文,并在当前调用者的上下文的基础上进行修改,制作新的函数堆栈,然后切换到函数的上下文。当函数执行结束,切换到调用者的上下文,让调用者继续执行协程调度。

qq_39519014的博客 1899

linux手册翻译——ucontext(3)

2021.06.22 13:42:47字数 213阅读 240 ucontext—— 用户线程上下文 Standard C Library (libc, -lc) #include <ucontext.h> /* Userlevel context. */ typedef struct ucontext_t { unsigned long int __ctx(uc_flags); struct ucontext_t *uc_link; sta...

chenzhjlf的专栏 350

ucontext-人人都可以实现的简单协程库

1.干货写在前面 协程是一种用户态的轻量级线程。本篇主要研究协程的C/C++的实现。 首先我们可以看看有哪些语言已经具备协程语义: 比较重量级的有C#、erlang、golang* 轻量级有python、lua、javascript、ruby 还有函数式的scala、scheme等。 c/c++不直接支持协程语义,但有不少开源的协程库,如: Protothreads:一个“蝇量级” C 语言协程库 libco:来自腾讯的开源协程库libco介绍,官网 coroutine:云风的一个C语言同步协程库,

INGNIGHT的专栏 807

ucontext实现协程

转载自:http://blog.youkuaiyun.com/qq910894904/article/details/41911175 目录(?)[+] 1.干货写在前面 协程是一种用户态的轻量级线程。本篇主要研究协程的C/C++的实现。 首先我们可以看看有哪些语言已经具备协程语义: 比较重量级的有C#、erlang、golang*轻量级有python、lua、j

ycf74514的专栏 645
上一篇: Linux 串口编程 中英文简体对照 1.0 版 Serial Programming HOWTO
下一篇: 制作一个基于yum/rpm管理方式的最小系统
CyberLabs
博客等级 码龄15年 143粉丝 7原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值