竞态条件和sigsupend函数

2023-12-03 15:32
文章标签 条件 函数 竞态 sigsupend

本文主要是介绍竞态条件和sigsupend函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

竞态条件(race condition)是一个在设备或者系统试图同时执行两个操作的时候出现的不希望的状况,但是由于设备和系统的自然特性,为了正确地执行,操作必须按照合适顺序进行。 

好比我们在模拟实现sleep()函数时

#include <stdio.h>
#include <signal.h>
#include <unistd.h>void handler(int s)
{}int mysleep(int sec)
{signal(SIGALRM,handler);alarm(sec);pause();int r=alarm(0);return r;
}
int main()
{mysleep(3);printf("3 sec \n");return 0;
}

这样实现基本可以完成sleep的功能,但在极端情况下,cpu负载很高,当程序刚刚执行完alarm(sec);这行代码时,时间片切给了另外一个进程,等回来时,alarm的时间已经到了,这时直接处理SIGALRM信号,执行信号处理函数,这些都进行完毕,才来继续执行pause()这句代码,因为信号已经在pause之前被处理过了,所以会一直阻塞在pause这里,而我们想要的是在pause()挂起时经过若干秒被SIGALRM信号打断然后pause返回,显然这与我们想要的结果相悖。

首先我们想到的是使用信号屏蔽来解决,在执行pause()之前一直屏蔽SIGALRM信号,等到即将执行pause时再解除屏蔽,但是这种做法似乎没效果,因为时间片也有可能在解除屏蔽与pause执行的间隙被切换出去,和上边做法没区别。。。

系统为我们提供了这么一个函数sigsuspend
int sigsuspend(const sigset_t* mask);
它相当于pause+信号屏蔽,是pause的加强版,可以用来解决竞态问题。
它的功能是在该函数执行期间用参数中传递 的信号屏蔽集覆盖原来的信号屏蔽集,函数执行完毕后又恢复为原来的信号屏蔽集。

小试一把先:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void handler(int s)
{printf("recv %d\n",s);sleep(3);printf("finish\n");
}
int main()
{signal(SIGINT,handler);signal(SIGQUIT,handler);sigset_t set;sigemptyset(&set);sigaddset(&set,SIGINT);sigprocmask(SIG_BLOCK,&set,NULL);sigset_t pset;sigemptyset(&pset);sigaddset(&pset,SIGQUIT);sigsuspend(&pset);sigprocmask(SIG_UNBLOCK,&set,NULL);
}

这里写图片描述

这时我们使用这个函数来处理mysleep中的竞态问题,在执行sigsupend之前屏蔽SIGALRM信号,在sigsupend的参数中传一个空的信号屏蔽集,即取消SIGALRM的屏蔽,这样就能使SIGALRM信号一定能够在sigsupend期间被处理。

#include <stdio.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handler(int s)
{}int mysleep(int sec)
{signal(SIGALRM,handler);sigset_t set;sigemptyset(&set);sigaddset(&set,SIGALRM);sigprocmask(SIG_BLOCK,&set,NULL);alarm(sec);sigset_t pset;sigemptyset(&pset);sigsuspend(&pset);sigprocmask(SIG_UNBLOCK,&pset,NULL);int r=alarm(0);return r;
}
int main()
{mysleep(3);printf("3 sec\n");
}

这篇关于竞态条件和sigsupend函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/449941

相关文章

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

SpringIntegration消息路由之Router的条件路由与过滤功能

《SpringIntegration消息路由之Router的条件路由与过滤功能》本文详细介绍了Router的基础概念、条件路由实现、基于消息头的路由、动态路由与路由表、消息过滤与选择性路由以及错误处理... 目录引言一、Router基础概念二、条件路由实现三、基于消息头的路由四、动态路由与路由表五、消息过滤

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

kotlin的函数forEach示例详解

《kotlin的函数forEach示例详解》在Kotlin中,forEach是一个高阶函数,用于遍历集合中的每个元素并对其执行指定的操作,它的核心特点是简洁、函数式,适用于需要遍历集合且无需返回值的场... 目录一、基本用法1️⃣ 遍历集合2️⃣ 遍历数组3️⃣ 遍历 Map二、与 for 循环的区别三、高

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st

MySQL中COALESCE函数示例详解

《MySQL中COALESCE函数示例详解》COALESCE是一个功能强大且常用的SQL函数,主要用来处理NULL值和实现灵活的值选择策略,能够使查询逻辑更清晰、简洁,:本文主要介绍MySQL中C... 目录语法示例1. 替换 NULL 值2. 用于字段默认值3. 多列优先级4. 结合聚合函数注意事项总结C