信号【N】-linux信号编程的buglist


前言

这片文章会持续更新在信号使用中遇到的bug:


一、sleep无法正常休眠

  • 问题描述
    再给后端的cpld发送命令,之后延时2s(sleep(2))读取cpld的特殊寄存器的数据,但总是错误的。但是使用两个sleep(2),就可以读取正确。即使第一个延时100s,不使用第二个sleep也不能正确读取。
    write()
    sleep(100)
    sleep(2)
    read()
    
  • 问题原因
    经过实验,从sleep(100)处返回时间还剩1s,也就是sleep(2)恰好不能被延时2s,提前收到信号中断返回了。再执行第二次sleep时,没有了信号,可以正常睡眠。
  • 解决办法
    为了避免这种情况,可以根据sleep的返回值,重新定义一个休眠函数,从而达到真正的睡眠时间。
    unsigned int time = 2;
    do{
    	time = sleep(time)
    }while(time > 0);
    
  • 深入理解sleep函数
    信号【3】- 理解sleep函数

二、接收到信号但是配置文件没有更新

  • 问题描述
    在项目中遇到一个问题:在设备信号线插拔测试的时候,信号线拔下来了,但是前端网页的状态并没有更新。以下是项目中的伪代码。

    进程:1
    void handler(int num)
    {
    	flag = 1;
    }
    int main(){
    	sigset_t prevMask,intMask;
    	struct sigaction sa;
    	sigemptyset(&intMask);
    	sigaddset(&intMask,SIGINT);
    	sigemptyset(&prevMask);
    	sa.sa_flags = 0;
    	sa.sa_handler = handler;
    	sigaction(SIGMIN,&sa,NULL);
    	while(1){
    		if(flag){
    			sigprocmask(SIG_BLOCK,&intMask,&prevMask);
    			/*以下为不希望被SIGMIN打断的关键代码*/
    			flag = 0;
    			read(fd,buff,128);
    			prase(buff);
    			update(json.config)
    			/*end 关键代码*/
    			/*恢复旧的掩码解除对SIGMIN的阻塞*/
    			sigprocmask(SIG_BLOCK,&prevMask,NULL);
    		}
    		pause();/*本意是希望进程能进入暂停状态,释放CPU资源,等待信号唤醒,继续执行*/
    	}
    }
    
  • 问题原因
    经过分析是,一旦第二次调用sigprocmask之后被阻塞的未决信号立即被传递,执行了信号处理函数,发送在pause之前,那么一旦进入pause则进程被阻塞,直到第二个实例到达为止。从而不能再执行文件更新的事件。
    这段代码本意是:解除对SIGMIN的阻塞并等待其第一次出现。

  • 解决办法
    为了避免这种情况,使用了sigsuspend的函数,将阻塞和挂起封装成一个原子操作。

    进程:2
    	void handler(int num)
    	{
    		flag = 1;
    	}
    	int main(){
    		sigset_t prevMask,intMask;
    		struct sigaction sa;
    		sigemptyset(&intMask);
    		sigaddset(&intMask,SIGINT);
    		sigemptyset(&prevMask);
    		sa.sa_flags = 0;
    		sa.sa_handler = handler;
    		sigaction(SIGMIN,&sa,NULL);
    		while(1){
    			if(flag){
    				sigprocmask(SIG_BLOCK,&intMask,&prevMask);
    				/*以下为不希望被SIGMIN打断的关键代码*/
    				flag = 0;
    				read(fd,buff,128);
    				prase(buff);
    				update(json.config)
    				/*end 关键代码*/
    				/*恢复旧的掩码解除对SIGMIN的阻塞*/
    				sigsuspend(NULL);/*原子操作*/
    				sigprocmask(SIG_BLOCK,&prevMask,NULL);
    			}
    		}
    	}
    
  • 深入理解sigsuspend函数
    信号【5】-理解sigsuspend

三、SIGBUS(Bus error singal 7)

3.1 背景

用mmap将文件映射到内存,读取文件时,提示“SIGBUS Bus ERROR”错误

3.2 分析

SIGBUS与SIGSEGV信号的一般区别如下

  • SIGBUS(Bus error)意味着所访问的地址为有效地址,但总线不能访问的地址,一般指的是位字节对齐的地址。
  • SIGSEGV(Segment error)意味着指所访问的地址为无效地址,没有物理地址相对应。
    初步判定通过open打开的共享文件大小为0,映射的内存大小和带写入的数据大小不一致。
(1) 打开文件并映射到内存
//文件不存在时创建
void* memory_malloc(size_t size, char *file)
{
    int fd = open(file, O_RDWR | O_CREAT, 0666);
    //修改文件大小,如果不指定,open默认创建的文件大小为0,导致BUS ERROR错误
    ftruncate(fd, size);

    void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    return p == (void*)-1 ? NULL : p;
}2) 从文件读取数据
 int64_t *p = static_cast<int64_t*>(file_malloc(sizeof(int64_t), file));
            if(p == NULL)
                return -1;          
        int64_t offset = *p;

 (3) 向文件写入数据
  int64_t* p = static_cast<int64_t*>(file_malloc(sizeof(int64_t), file));
  if(p == NULL)
      return -1;
  *p = 222;

https://blog.csdn.net/m0_46535940/article/details/124908464

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值