协程 C/C++ 扩展开发指南(1):内存安全

代码绘云师
• 阅读 7796

Swoole4 协程的出现使得 PHP 底层上从原来串行模式变成了并发模式。有很多 PHP 的C/C++扩展在开发时未能考虑到并发性、可重入问题,导致无法在Swoole协程中使用。本文会详细讲解如何编写协程并发安全的C/C++代码。

可重入性

示例代码:

int t;

void test1(int *x, int *y) {
    t = *x;
    *x = *y;
    //fun1 函数中可能会存在协程切换
    fun1();
    //错误代码
    *y = t;
}
  • t是一个全局变量或者static静态变量
  • 在协程A中调用了test1函数,使用了全局变量t
  • 当函数内调用了fun1(),这个函数中如果发生了协程切换,这时假如另外一个协程B也执行了test1函数,那么t的值可能会被修改
  • 协程B挂起时,重新回到协程A,这时*y = t,会得到一个错误的值

引用栈内存

这也是一个严重的风险点。协程1将自身栈内存的指针发送给另外一个协程2,协程1退出时会释放协程栈内存。协程2的生命周期长于1,继续读写此内存,就会导致segment fault

示例:

void co1() {
    char buf[2048];
    //这里启动一个新的协程,buf 是协程1栈上内存
    co2(buf);
    //协程1 退出时会释放栈内存
}

void co2(char *buf) {
    for(int i=0; i<2048; i++) {
        Coroutine::sleep(1);
        //这里 buf 内存可能已经释放了
        buf[i] = 1;
    }
}

协程安全代码

为了保证安全性,在Swoole4协程编程中:

  • 不要使用static变量和全局变量,坚持只用局部变量
  • 若必须访问全局变量,必须保证只用于计算逻辑,不得存在任何IOSleep等引起协程切换的操作
  • 不调用其它任何不可重入的函数
  • 不要引用栈上内存
点赞
收藏
评论区
推荐文章
HelloWorld官方 HelloWorld官方
5年前
Go Context 并发编程简明教程
1为什么需要ContextWaitGroup和信道(channel)是常见的2种并发控制的方式。如果并发启动了多个子协程,需要等待所有的子协程完成任务,WaitGroup非常适合于这类场景,例如下面的例子:varwgsync.WaitGroupfuncdoTask(nint){time.Sleep(time.Durat
风斗 风斗
4年前
Kotlin 协程中,关于 runBlocking, launch ,withContext ,async,doAsync 之间的简单区别
引入大佬的话,Kotlin的协程,本质上是一个线程框架,它可以方便的切换线程的上下文(如主线程切换到子线程/子线程切回主线程)。而平时我们要想在AndroidStudio使用协程,先要在gradle引入协程依赖:implementation"org.jetbrains.kotlinx:kotlinxcoroutinescore:1.3.3"
Wesley13 Wesley13
4年前
Go语言
发现问题今天在看代码的时候,遇见了多个协程写同一个slice的情况,发现未对slice做任何保护,亦未使用其他手段保证并发安全,这样肯定会出错的。思考slice不是协程安全的,所以在多个协程中读写slice是不安全的,在高并发的情况下会产生不可控制的错误。总结这里记录一下错误的使用方式与正确的使用方式:错误的使用
Wesley13 Wesley13
4年前
go 协程
packageutilsimport("bytes""fmt""runtime""strconv")_/\__获取协程__ID\/_funcGetGoroutineID(){b:make(\\byte,64)b\b\:runtime.Stack(b,false)\b\
Stella981 Stella981
4年前
Gevent简明教程
1、前述进程线程协程异步并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。多进程编程在python中有类似C的os.fork,更高层封装的有multiprocessing标准库多线程编程python中有Thread和threading异步编程在linux下主要有三种实现selec
Stella981 Stella981
4年前
Goroutine(协程)为何能处理大并发?
简单来说:协程十分轻量,可以在一个进程中执行有数以十万计的协程,依旧保持高性能。进程、线程、协程的关系和区别:进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。协程和线程一样共享堆
Wesley13 Wesley13
4年前
Go 并发
Go并发并发指的是同时处理多个任务的能力。并行指的是并行处理多个任务的能力。并行不一定加快运行速度,因为并行组件之间可能需要互相通信。Go中使用协程,信道来处理并发。协程Go中主要通过协程实现并发。协程是与其他函数或方法一起并发运行的函数或方法,协程可以看作是轻量级线程,但是创建成本更小,我们经常
Easter79 Easter79
4年前
Swoole2.0内置协程并发测试
Swoole2.0是一个革命性的版本,它内置了协程的支持。与Go语言协程不同,Swoole协程完全不需要开发者添加任何额外的关键词,直接以过去最传统的同步阻塞模式编写代码,底层自动进行协程调度实现异步IO。使并发编程变得非常简单。最新的版本中,内置协程已支持PHP7,同时兼具了性能和并发能力,Swoole的强大超乎想象。本文基于Github最新的Sw
Android Kotlin 协程初探 | 京东物流技术团队
1它是什么(协程和Kotlin协程)1.1协程是什么维基百科:协程,英文Coroutine\2为什么选择它(协程解决什么问题)异步场景举例:1.第一步:接口获取当前用户token及用户信息2.第二步:将用户的昵称展示界面上3.第三步:然后再通过这个toke