linux在使用重定向写入文件时(使用标准C库函数时)使处理信号异常(延时)--问题分析

linux在使用重定向写入文件时(使用标准C库函数时)使处理信号异常(延时)--问题分析

在使用alarm函数进行序号处理测试的时候发现如果把输出重定向到文件里面会导致信号的处理出现严重的延迟(ubuntu18)

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(void){
	alarm(3);//定时三秒
	while(1){
		int i;
		printf("%d\n", i++); //打印信息
	}
	return 0;
}

测试

  • 正常情况

使用命令time ./a.out进行计时

这时候这是个时间是基本没有误差的

  • 出现问题

这时候使用命令time ./a.out > text.out把输出的信息放到文件里面

这时候就会发现这一个处理的时间开始不对劲了

尝试分析

库函数分析

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(void){
	alarm(3);
	printf("now alarm  = %d\n", alarm(3));
	while(1){
		char buf[20];
		int i;
		sprintf(buf, "%d\n", i++);
		write(STDOUT_FILENO, buf, strlen(buf));
	}
	return 0;
}

把这一个输出使用系统调用进行

这里可以看出延时少了很多

查看实际的系统调用

使用命令strace ./a.out > out.txt查看实际的系统调用

  • 库函数版本(shell)

  • 库函数版本(文件)

  • 系统调用版本(shell)

  • 系统调用版本(文件)

这时候可以发现这库函数进行文件写入的时候是使用了一个缓存区4096字节

测试缓冲区大小对信号处理的影响

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(void){
	alarm(3);
	printf("now alarm  = %d\n", alarm(3));
	while(1){
		int i;
		printf("%d ", i++);//不使用换行, 这时候库函数会使用大的缓冲区
	}
	return 0;
}


这时候可以获取结论这一个不是因为缓冲区大小出现的, 写入shell的时候使用的是1024的缓冲区, 但是对于时间的影响不大

write函数分析

在man文档里面的write里面有这样一段话

If a write() is interrupted by a signal handler before any bytes are written, then the call fails with the error EINTR; if it is interrupted after at least one byte has been written, the call succeeds, and returns the number of bytes written.

从这一段可以推测出write不是原子操作, 并且这一个是可以被信号打断的, 并且实际测试写shell的时候是随时可以使用Ctrl + C打断的, 只有在文件处理的时候会出现Ctrl + C无法立刻打断这一个程序

信号处理分析

信号处理分析

从这一篇文章里面可以获取信号处理是在从内核态返回的时候处理的

推测结论

猜测可能是内核在对文件处理的时候会把很多的write里面的信息合并起来处理(就算是4096处理一次从跟踪可以看出来也是有很多次的, 如果每一处只处理一个4096不至于出现延时达到好几秒的情况), 写入shell的时候没有进行合并, 所以误差比较小, 这时候由于硬盘的写入比较慢, 数据量比较大, 需要等待IO, 会长时间处于内核态, 导致信号处理的延时

使用write每一次写入的数量比较少的时候反应比较快, 推测这一个合并可能是和write的次数也有关系

这一段仅供参考, 没有实际查看源码, 回头分析源码以后会再补充的

相关推荐
hkj88086 小时前
Linux 总线-设备-驱动(Bus-Device-Driver)完整协作原理
linux·运维·microsoft
bu_shuo7 小时前
c与cpp中的argc和argv
c语言·c++·算法
早点睡啊Y7 小时前
深入学 LangChain 官方文档(一):总览、安装与快速开始
linux·服务器·langchain
梦想的旅途27 小时前
JavaScript 实现企业微信消息自动发送的技术实践
运维·javascript·自动化·企业微信
Aurorar0rua7 小时前
CS50 x 2024 Notes Algorithms - 02
c语言·开发语言·学习方法
优橙教育7 小时前
5G网优工程师证书怎么选:HCSP/HCIA/5G认证全解析
运维·服务器
光影6277 小时前
MySQL基础入门
数据库·笔记·sql·学习·mysql·学习方法
国产化创客8 小时前
Kindle完整越狱改造:从闲置泡面盖到Linux开发与智能家居终端
linux·运维·物联网·嵌入式·智能家居·智能硬件
足球中国8 小时前
nuget把缓存搬离C盘
c语言·windows·缓存
qetfw8 小时前
CentOS 7 搭建 MariaDB 数据库服务
linux·数据库·centos·mariadb