从coobjc理解协程

2019-03-09  本文已影响14人  Boothlee

前言:

自己对协程的概念的理解,源于coobjc的开源。文章参考了其他人对于协程的理解,加以融合贯通,希望能对不了解协程的人给予理解上的帮助。

协程的概念可能很多人不熟悉,第一次听到这个词,可能是这样:

什么是协程.jpg

完整的漫画在这里。

看完漫画,可能对协程有了初步的了解,至少知道除了订机票,还能编程~

理解协程,要先明确一个概念:用户态线程

引用一段话加以说明:

了解了用户态线程,就对理解协程更近了一步

协程它能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。普通过程(函数)可看成这个特殊过程的一个特例:只有一个状态,每次进入时局部状态重置。

下面结合coobjc理解一下协程如何控制,切换状态:

上面说的调用状态,我理解成线程的寄存器状态,协程的操作其实就是记录寄存器状态到对应的上下文中,继而通过上线文,控制协程的操作。在coobjc中对应的应该就是coroutine_ucontext_t
对应的启动,切换控制权,恢复就是通过操作coroutine_ucontext_t,核心API如下
coobjc 协程实现的核心在
core/coroutine_context 中,点开头文件,可以看到

//获取协程上下文
extern int coroutine_getcontext (coroutine_ucontext_t *__ucp);
//设置协程上下文
extern int coroutine_setcontext (coroutine_ucontext_t *__ucp);
//设置协程上下文
extern int coroutine_begin (coroutine_ucontext_t *__ucp);
//创建协程上下文
extern void coroutine_makecontext (coroutine_ucontext_t *__ucp, IMP func, void *arg, void *stackTop);

这里使用汇编实现了上下文的获取、设置:

#if defined(__arm64__) || defined(__aarch64__)

.text
.align 2
.global _coroutine_getcontext
_coroutine_getcontext:
    stp    x18,x19, [x0, #0x090]
    stp    x20,x21, [x0, #0x0A0]
    stp    x22,x23, [x0, #0x0B0]
    stp    x24,x25, [x0, #0x0C0]
    stp    x26,x27, [x0, #0x0D0]
    str    x28, [x0, #0x0E0];
    stp    x29, x30, [x0, #0x0E8];  // fp, lr
    mov    x9,      sp
    str    x9,      [x0, #0x0F8]
    str    x30,     [x0, #0x100]    // store return address as pc
    stp    d8, d9,  [x0, #0x150]
    stp    d10,d11, [x0, #0x160]
    stp    d12,d13, [x0, #0x170]
    stp    d14,d15, [x0, #0x180]
    mov    x0, #0                   
    ret

.global _coroutine_begin
_coroutine_begin:
    ldp    x18,x19, [x0, #0x090]
    ldp    x20,x21, [x0, #0x0A0]
    ldp    x22,x23, [x0, #0x0B0]
    ldp    x24,x25, [x0, #0x0C0]
    ldp    x26,x27, [x0, #0x0D0]
    ldp    x28,x29, [x0, #0x0E0]
    ldr    x9,     [x0, #0x100]  // restore pc into lr
    mov    x30,   #0;
    ldr    x1,      [x0, #0x0F8]
    mov    sp,x1                  // restore sp
    ldp    d8, d9,  [x0, #0x150]
    ldp    d10,d11, [x0, #0x160]
    ldp    d12,d13, [x0, #0x170]
    ldp    d14,d15, [x0, #0x180]
    ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
    ret    x9

.global _coroutine_setcontext
_coroutine_setcontext:
    ldp    x18,x19, [x0, #0x090]
    ldp    x20,x21, [x0, #0x0A0]
    ldp    x22,x23, [x0, #0x0B0]
    ldp    x24,x25, [x0, #0x0C0]
    ldp    x26,x27, [x0, #0x0D0]
    ldp    x28,x29, [x0, #0x0E0]
    ldr    x30,     [x0, #0x100]  // restore pc into lr
    ldr    x1,      [x0, #0x0F8]
    mov    sp,x1                  // restore sp
    ldp    d8, d9,  [x0, #0x150]
    ldp    d10,d11, [x0, #0x160]
    ldp    d12,d13, [x0, #0x170]
    ldp    d14,d15, [x0, #0x180]
    ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
    ret    x30

最后列举一点协程的优点

协程没有线程的切换,省去了切换线程需要的开销,这是协程对比多线程的优势。协程不是多线程,自然也舍去了加锁,解锁的操作。但是协程通过代码的控制逻辑,中断,恢复任务。

参考:

coobjc

协程的好处有哪些?

阿里开源 iOS 协程开发框架 coobjc源码分析

上一篇 下一篇

猜你喜欢

热点阅读