未向内核赠予缓冲区时复用vmsplice缓冲区出现输出乱序问题
问题根因
你对vmsplice的调用返回语义理解存在偏差:无标志位时的阻塞返回,仅代表提交的内存范围已经被加入管道待读队列,不代表数据已经被下游消费,也不代表内核已经单独拷贝了一份数据。内核会直接持有你传入的用户态内存页的引用,直到对应管道数据被消费后才会释放。
现象解释
- 加
sleep(1)时输出正常:1秒的等待窗口足够下游cat读取完所有管道排队数据,内核已经释放了对栈上buffer的引用,此时你再修改buffer[0]不会影响已被读走的内容,所以输出按顺序递增。 - 去掉
sleep后乱序:循环执行速度远快于管道消费速度,vmsplice返回后你立刻修改buffer的值,此时前几次甚至十几次提交到管道的buffer引用还未被消费,内核返回给cat的就是修改后的新值,自然会出现跳号、重复、乱序。
解决方案
可任选以下方案修复问题:
- 每次循环申请独立的缓冲区,不复用同一块内存,避免后续修改影响未消费的排队数据
- 调用
vmsplice时传入SPLICE_F_GIFT标志,明确将缓冲区所有权赠予内核,调用后不可再修改对应缓冲区 - 调用
vmsplice后增加同步逻辑,等待对应管道内容被消费完成后再修改缓冲区
内容的提问来源于stack exchange,提问作者NougatRillettes
相关产品推荐
相关产品推荐

