Linux 信号之mysleep

一、    用alarm和pause实现sleep(3)函数,称为mysleep。

 

1. main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数sig_alrm。

2. 调用alarm(seconds)设定闹钟。

3. 调用pause等待,内核切换到别的进程运行。

4. seconds秒之后,闹钟超时,内核发SIGALRM给这个进程。

5. 从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数 是sig_alrm。

6. 切换到用户态执行sig_alrm函数,进入sig_alrm函数时SIGALRM信号被自动屏蔽, 从sig_alrm函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入 内核,再返回用户态继续执行进程的主控制流程(main函数调用的mysleep函数)。

7. pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理 动作。

              #include <stdio.h>

#include <signal.h>

#include <unistd.h>

 

void sig_alarm(int signo)//信号处理函数

{}

 

int mysleep(int seconds)

{

structsigaction act, oact;

act.sa_handler= sig_alarm;

sigemptyset(&act.sa_mask);

act.sa_flags= 0;

sigaction(SIGALRM,&act, &oact);//注册信号处理函数

 

alarm(seconds);//设置闹钟

pause();

int_time = alarm(0);//清空闹钟

sigaction(SIGALRM,&oact,NULL);//恢复默认信号处理动作

return_time;

}

 

int main()

{

while(1)

{

        printf("iam sleeping !\n");

        mysleep(3);

 

}

return0;

}

运行结果:每3秒打印一条语句


缺陷:在闹钟设置之后,响应之前被切出去,再过3秒再切回来,就将永远收不到信号,进程将被永远挂起。

思考问题:

1、           信号处理函数sig_alrm什么都没⼲干,为什么还要注册它作为SIGALRM的处理函数?不注册信号处 理函数可以吗?

信号处理机制:

用函数signal注册一个信号捕捉函数。原型为:


#include 
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
 
signal 的第1个参数signum表示要捕捉的信号,第2个参数是个函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DEF(表示交由系统缺省处理,相当于白注册了)或SIG_IGN(表示忽略掉该信号而不做任何处理)。signal如果调用成功,返回以前该信号的处理函数的地址,否则返回 SIG_ERR。


sighandler_t是信号捕捉函数,由signal函数注册,注册以后,在整个进程运行过程中均有效,并且对不同的信号可以注册同一个信号捕捉函数。该函数只有一个参数,表示信号值。

示例:

1)、  捕捉终端CTRL+c产生的SIGINT信号:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
 
void SignHandler(int iSignNo)
{
    printf("Capture sign no:%d/n",iSignNo); 
}
 
int main()
{
    signal(SIGINT,SignHandler); 
    while(true) 
        sleep(1); 
    return 0; 
}
该程序运行起来以后,通过按CTRL+c将不再终止程序的运行。应为CTRL+c产生的SIGINT信号已经由进程中注册的SignHandler函数捕捉了。该程序可以通过Ctrl+/终止,因为组合键Ctrl+/能够产生SIGQUIT信号,而该信号的捕捉函数尚未在程序中注册。

 

2)、  忽略掉终端CTRL+c产生的SIGINT信号:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
 
int main()
{
    signal(SIGINT,SIG_IGN); 
    while(true) 
        sleep(1); 
    return 0; 
}
该程序运行起来以后,将CTRL+C产生的SIGINT信号忽略掉了,所以CTRL+C将不再能是该进程终止,要终止该进程,可以向进程发送SIGQUIT信号,即组合键CTRL+/
 
3)、  接受信号的默认处理,接受默认处理就相当于没有写信号处理程序:
 
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
 
int main()
{
    signal(SIGINT,DEF); 
    while(true) 
        sleep(1); 
    return 0; 
}

2、为什么在mysleep函数返回前要恢复SIGALRM信号原来的sigaction?

 

        当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么它会被阻塞到当前处理结束为止。

 

 

 

二、  sigsuspend实现mysleep 函数:

 

对于第一个版本的mysleep , 出现这个问题的根本原因是系统运行的时序(Timing)并不像我写程序时所设想的那样。虽然alarm(nsecs)紧接着的下⼀行就是pause(),但是⽆无法保证pause()⼀一定会在调用alarm(nsecs)之后的nsecs秒之内被调⽤用。由于异步事件在任何时候都有可能发⽣生(这⾥的异步事件指出现更高优 先级的进程),如果我们写程序时考虑不周密,就可能由于时序问题而导致错误,这叫做竞态条件 (Race Condition)。

 

sigsuspend包含了pause的挂起等待功能,同时解决了竞态条件的问题,在对时序要求严格的场合下都应该调⽤用sigsuspend而不是pause。

 

#include <signal.h>

int sigsuspend(const sigset_t *sigmask);

 

和pause⼀一样,sigsuspend没有成功返回值,只有执⾏行了⼀一个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。

 

调⽤用sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除 对某 个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,从sigsuspend返回后仍然是屏蔽的。

 

以下⽤用sigsuspend重新实现mysleep函数:

1、         屏蔽SIGALARM信号

2、         alarm(seconds);

3、         解除对SIGALARM信号的屏蔽。

4、         挂起等待pause();

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

 

void sig_alarm(int signo)

{}

 

int mysleep(int seconds)

{

       structsigaction act, oact;

       sigset_tnewmask, oldmask, suspmask;

//设置信号处理函数,保存以前的信息

       unsignedint unslept;

       act.sa_handler= sig_alarm;

       sigemptyset(&act.sa_mask);

       act.sa_flags= 0;

       sigaction(SIGALRM,&act, &oact);

   //阻塞信号,保存当前的信号屏蔽字

       sigemptyset(&newmask);

       sigaddset(&newmask,SIGALRM);

       sigprocmask(SIG_BLOCK,&newmask, &oldmask);

       //屏蔽SIGALRM

       alarm(seconds);

       suspmask= oldmask;

       sigdelset(&suspmask,SIGALRM);

       sigsuspend(&suspmask);

//解除屏蔽,挂起等待//SIGALRM信号递达后,sigsuspend返回,自动恢复原来的屏蔽字,自动恢复原来的屏蔽字,即再次屏蔽SIGMASK

int _time =alarm(0);

       sigaction(SIGALRM,&act, NULL);

//恢复默认的信号处理动作

       sigprocmask(SIG_SETMASK,&oldmask, NULL);

      //重置信号屏蔽字,再次解除对SIGALRM的屏蔽。

       return_time;

}

 

int main()

{

       while(1)

       {

              mysleep(5);

              printf("iam sleeping !\n");

       }

       return0;

}

 

运行结果:每隔五秒响应动作,打印语句。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459414.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA 操作系统已经来到第五个版本了 现陆续放出三个版本 这是第二个版本

1 package System2;2 3 import javax.swing.*;4 5 import java.awt.*;6 import java.awt.event.ActionEvent;7 import java.awt.event.ActionListener;8 import java.awt.event.KeyListener;9 import java.util.*;10 /**11 * 作者:范铭祥12 * 内容及功能&#xff1a; 显示框…

标准Web系统的架构分层

1、架构体系分层图 在上图中我们描述了Web系统架构中的组成部分。并且给出了每一层常用的技术组件/服务实现。需要注意以下几点&#xff1a; 系统架构是灵活的&#xff0c;根据需求的不同&#xff0c;不一定每一层的技术都需要使用。例如&#xff1a;一些简单的CRM系统可能在产…

数据链路层差错检测:CRC(循环冗余检验)

1、循环冗余检验&#xff08;CRC&#xff09;&#xff1a; 在发送端&#xff0c;先把数据划分为祖&#xff0c;假定每组K个比特。现假定待传送的数据M 101001&#xff08;k6&#xff09;。CRC运算就是在数据M后面添加提供差错检测的n位冗余码&#xff0c;然后构成一个帧发送出…

算法导论笔记:25所有节点对的最短路径问题

本章考虑在给定的有向加权图G(V, E)&#xff0c;对于所有的节点u,v∈V&#xff0c;找到一条从节点u到节点v的最短路径。希望以表格的形式表示输出&#xff1a;第u行第v列给出的是节点u到节点v的最短路径权重。 对于这个问题&#xff0c;如果是运行|V|次单源最短路径算法来解决所…

iOS开发~UI布局(二)storyboard中autolayout和size class的使用详解

一、概要&#xff1a;前一篇初步的描述了size class的概念&#xff0c;那么实际中如何使用呢&#xff0c;下面两个问题是我们一定会遇到的&#xff1a;1、Xcode6中增加了size class&#xff0c;在storyboard中如何使用&#xff1f; 2、auto layout该如何与size class配合来进行…

Linux:守护进程解析、如何实现守护进程

1、守护进程&#xff1a; 守护进程也称精灵进程&#xff08;Daemon&#xff09;&#xff0c;是运行在后台的⼀一种特殊进程。它独立于控制终端且周期性地执行某种任务或等待处理某些发生的事件。守护进程是⼀一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如…

CAS实现单点登录方案(SSO完整版)

一、简介 1、cas是由耶鲁大学研发的单点登录服务器 2、本教材所用环境 Tomcat7.2JDK1.7CAS Service 版本 cas-server-3.4.8-releaseCAS Client版本 cas-client-3.2.1-release 二、生成证书 证书对于实现此单点登录非常之重要&#xff0…

PHP、C#、通用的DES加密

2019独角兽企业重金招聘Python工程师标准>>> PHP class JoDES {private static $_instance NULL;/*** return JoDES*/public static function share() {if (is_null(self::$_instance)) {self::$_instance new JoDES();}return self::$_instance;}/*** 加密* para…

如何防止头文件被重复包含或引用?

一、#pragma once ( 比较常用&#xff09; 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次&#xff0c;这条指令实际上在VC6中就已经有了&#xff0c;但是考虑到兼容性并没有太多的使用。 #pragmaonce是编译相关&#xff0c;就是说这个编译系统上能用&#xff…

如何解决类模板的分离编译问题?

一模板&#xff1a; 模板不是数据类型&#xff0c;只能算是一种行为集合的表示。编译器在使用模板时&#xff0c;通过更换模板参数来创建数据类型。这个过程就是模板实例化(Instantiation)&#xff0c; 从模板类创建得到的类型称之为特例(specialization)&#xff0c;说白了就是…

结对项目 刘静 201303014059 计科高职13-2

结对&#xff1a;人&#xff1a;孙帅 博客地址&#xff1a; http://www.cnblogs.com/s3366181/p/4509260.html一、 题目简介 1.所选题目&#xff1a;输出圆的面积 2.编程工具&#xff1a;Eclipse 3、实现功能&#xff1a;用户给定一圆的半径运行程序系统会给出给定半径圆的面…

弹出div或者弹出新窗口的固定位置、固定大小

2019独角兽企业重金招聘Python工程师标准>>> js代码&#xff1a; //打开一个新窗口&#xff0c;固定的位置&#xff0c;固定的大小 //window.open("push_add.html",newwindow, height550, width1000, top200, left500, toolbarno, menubarno, scro…

NAT(网络地址转换)技术与代理服务器原理

一、 Nat技术&#xff1a; NAT英文全称是“Network Address Translation”&#xff0c;中文意思是“网络地址转换”&#xff0c;它是一个IETF(Internet Engineering Task Force,Internet工程任务组)标准&#xff0c;允许一个整体机构以一个公用IP&#xff08;Internet Prot…

原 Linux搭建SVN 服务器2

原 Linux搭建SVN 服务器 发表于1年前(2014-08-05 17:55) 阅读&#xff08;12257&#xff09; | 评论&#xff08;3&#xff09; 31人收藏此文章, 我要收藏赞3摘要 Linux搭建SVN 服务器目录[-] Linux搭建SVN 服务器1 安装SVN2 使用客户端连接2.1 使用…

网络层核心:路由和路由生成算法

一、路由和路由算法简介&#xff1a; 路由就是通过互连的网络把信息从源地址传送到目的地址的活动。路由发生在OSI网络参考模型的第三层即网络层。 路由引导封包转送&#xff0c;经过一些中间的节点后&#xff0c;到达目的地。把该功能做成硬件的话称为路由器。路由通常根据路…

网络:常见的端口号及分类

一、端口号概念 在网络技术中&#xff0c;端口&#xff08;Port&#xff09;包括逻辑端口和物理端口两种类型。物理端口指的是物理存在的端口&#xff0c;如ADSL Modem、集线器、交换机、路由器上用 于连接其他网络设备的接口&#xff0c; 如RJ-45端口、SC端口等等。逻辑端口…

EditPlus 技巧大全:[1]怎么配置PHP编译环境

editplus是一款小巧但功能强大易扩展的文本编辑器&#xff0c;可以通过设置用户工具将其作为C,Java,Php等等语言的一个简单的IDE。 工具/原料 EditPlus v3.3.1 php 5.3.14 方法/步骤 1.打开editplus 2.点击菜单栏“工具” 3.选择下拉菜单的“配置用户工具”&#xff0c;进入配置…

网络:传输层 TCP报文格式解析

一、TCP报文格式 1、为了提供可靠的数据传输&#xff0c;TCP报文首部字段有较多的字段&#xff0c;TCP报文格式如下图&#xff1a; 图2 TCP报文格式 16位源和目标端口&#xff08;16位&#xff09;&#xff1a;用于多路复用/多路分解来自或送至上层应用的数据&#xff0c;可以…

MATLAB图像小波变换

为什么80%的码农都做不了架构师&#xff1f;>>> 小波变换与小波包变换 人脸图像f(x,y) 的一层小波变换如下图所示&#xff1a; 图中L 和H 分别表示低通滤波器和高通滤波器&#xff0c;l(n) 和h(n) 分别表示它们相应的脉冲响应&#xff0c;2↓1表示降2采样fLL和fHH分…

grunt之Gruntfile(1)

grunt 执行的时候&#xff0c;他会找该目录下的Gruntfile文件&#xff0c;所以&#xff0c;要在目录下创建Gruntfile文件。 下面我demo一个copy任务&#xff1a; 执行copy&#xff0c;首先我们要一个copy的模块&#xff0c;那么我们先安装下copy模块 首先&#xff0c;我到H盘&a…