无栈协程:用户态的Linux进程调度

2023-01-06 0 645

PulseAudio(coroutine),是为的是把epoll触发器该事件变为并行的一类程式设计商业模式。

它的再次出现也设点一两年的事,是随著go词汇而明确提出的一类程式设计商业模式。

即使触发器该事件程式设计的时效性较为差,接着就有了PulseAudio。

PulseAudio,也被称作采用者态的民主化

PulseAudio的运维,跟LinuxMach对民主化的运维是类似于的。

1,无论是PulseAudio、民主化、缓存,它都有两个要运转的表达式,和有关的语句

表达式是它要运转的标识符,语句是它的运转状况

pthread库对缓存表达式的表述是void* (*run)(void*),它是两个模块和codice都是void*的表达式指针:

那么表述的缓存表达式,能给它传达任何人类别任何人类别的codice。

那个表达式,是线程要运转的表达式。

假如是民主化不然,main()表达式是它要运转的民主化表达式

任何人不采用fork()控制系统初始化的民主化,都从main()表达式开始运转的。

fork()控制系统初始化后的(父)子民主化,会运转fork()回到后的标识符,比如:

pid_t cpid = fork();

if(-1== cpid) printf(“fork error\n”);

else if(0== cpid) { //子民主化的标识符 }

else{ //父民主化接下来的标识符}

PulseAudio也跟民主化、缓存类似于,也有两个要运转的表达式。

另外,无论民主化、缓存、PulseAudio都有两个运转的状况语句

那个语句里最重要的数据,是

无栈协程:用户态的Linux进程调度

LinuxMach的民主化的内存布局

表达式的局部变量是分配在栈上的,表达式初始化的回到地址也是在栈上的,各种寄存器也是保存在栈上的。

对于两个正在运转的表达式来说,必须是独立的,不能与其他表达式共享:即使运转着的表达式会随时修改栈上的数据。

无论是缓存、民主化、PulseAudio,都是这样。

同两个民主化内的不同缓存之间虽然会共享全局变量和内存,但不能共享的。

在Linux上,缓存和民主化除了共享全局变量和堆之外,基本上是一回事。

LinuxMach里,它都用上图的数据结构描述:

1)最早是4096字节(1个内存页),后来扩展到8k字节(2个页)。

2)这8k内存的低地址民主化的描述结构,也是main()表达式运转时需要的信息。

这8k内存的高地址,是民主化在Mach里运转时(比如执行控制系统初始化时)的(Mach)

这两部分加起来,是民主化的语句

所以,在给LinuxMach写模块时,标识符里不能采用很大的局部变量,以免把民主化的描述结构给覆盖了

char buf[4096];

这样的代码是不能写在Mach里的,即使局部变量的内存是分配在栈上的,而Mach给每个民主化配备的栈都很小(8k)。

这两个buf数组就占了4k,那表达式初始化稍微复杂一点,就可能把低地址的民主化结构给覆盖了。

LinuxMach在调度民主化的时候,是不断地切换上图的数据结构,从而让多个民主化能交替运转

即使运维间隔远小于人眼能察觉的时间间隔,所以即使在单核CPU上,在人看来也是多民主化同时运转的。

2,PulseAudio的实现,

多个PulseAudio要想在采用者态交替运转,也必须为每个PulseAudio配备不同的栈

多个PulseAudio都隶属于同两个民主化,而民主化栈的位置是被操作控制系统提前分配好了的。

所以,为每个PulseAudio配备栈的时候,每个栈的内存范围必须在民主化栈的范围内。

无栈协程:用户态的Linux进程调度

有栈PulseAudio的内存布局

如上图:

你说要在“民主化”的栈上给PulseAudio提前开多大的空间?

每个PulseAudio的栈又要预留多大?

预留小了,PulseAudio表达式的局部变量把PulseAudio的描述结构覆盖了的事,也会发生的。

预留大了,同两个民主化所能支持的总PulseAudio数就会减少

而且,程序员的采用者态标识符一般都比Mach标识符更粗放

写个采用者态标识符,还不让我那么开缓冲区charbuf[1024*1024],能行吗?[捂脸]

没有哪个程序员愿意,写个采用者标识符还像写Mach驱动一样战战兢兢的。

所以,有栈PulseAudio的劣势非常明显!

1)首先,每个民主化支持的PulseAudio个数是有限的,而不是无限的。

大多数情况下,虽然采用者标识符要开的PulseAudio个数也不至于突破上限,但毕竟它是个有限集,不是个可数集

这对采用者标识符的限制还是较为大的。

有那么个限制,在创建PulseAudio的时候就要每次都检查是否成功。

标识符是这样的:

int ret = coroutine_create();

if (ret < 0) {

printf(“error\n”);

return -1;

而不是这样的:

coroutine_create();

否则标识符就不完善,即使没有处理异常情况。

2)万一PulseAudio表达式里有复杂的递归,PulseAudio的栈溢出了,那么就可能覆盖多个PulseAudio的数据,导致程序挂了。

能预见,这种挂的位置几乎肯定不是第一现场

这种BUG查起来,还是非常麻烦的。

不挂在第一现场的内存BUG,都是C词汇里很难查的BUG,它很大可能是随机的[捂脸]

接着,就有了无栈PulseAudio。

3,无栈PulseAudio,

无栈PulseAudio的实现也很简单,只要在切换PulseAudio之前,把当前PulseAudio栈数据保存到堆上就能了。

每个PulseAudio的语句都是用malloc()申请的堆内存,在语句里预留两个空间,在切换PulseAudio时把(当前PulseAudio的)栈数据保存到那个预留空间里。

当PulseAudio再次被运维运转时,把上次的栈数据从(PulseAudio的)语句里复制到民主化栈上,PulseAudio就能再次运转了。

无栈协程:用户态的Linux进程调度

无栈PulseAudio的内存布局

如上图,PulseAudio0挂起,PulseAudio1被运维运转:

1)先把民主化栈上的数据复制到PulseAudio0的上下文里。

这时民主化栈上的数据,全是PulseAudio0的栈数据。

PulseAudio的语句是malloc()申请的堆内存,假如栈数据太大不然,是能用realloc()再次分配更大的内存的。

这就打破了PulseAudio栈的大小固定的缺陷。

每个协程能采用的栈大小,只受制于民主化的栈的大小。

2)当PulseAudio的栈不再受到限制后,能创建的PulseAudio数量也只受制于民主化的堆的大小。

只有整个民主化堆内存被耗尽后,PulseAudio的创建和运转才会没法进行。

我在scf编译器框架里附带的那个PulseAudio的实现,是无栈PulseAudio[呲牙]

它在scf/coroutine目录。

2021年的5月份我就想到了这些问题,并且给了解决的标识符,在githubgitee的scf标识符都有。

2022年以来,我没往github上更新标识符,目前gitee上的scf是最新的。

老外最近又开始吹无栈PulseAudio了是吧[捂脸]

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务