Linux下C语言编程--信号处理函数

前言:这一章我们讨论一下Linux下的信号处理函数.
Linux下的信号处理函数:
1.信号的产生
2.信号的处理
3.其它信号函数
--------------------------------------------------------------------------------
一个实例
1。信号的产生
Linux下的信号可以类比于DOS下的INT或者是Windows下的事件.在有一个信号发生时候相信的信号就会发送给相应的进程.在Linux下的信号有以下几个. 我们使用 kill -l 命令可以得到以下的输出结果:

1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR

关于这些信号的详细解释请查看man 7 signal的输出结果. 信号事件的发生有两个来源:一个是硬件的原因(比如我们按下了键盘),一个是软件的原因(比如我们使用系统函数或者是命令发出信号). 最常用的四个发出信号的系统函数是kill, raise, alarm和setitimer函数. setitimer函数我们在计时器的使用 那一章再学习.
#include
#include
#include

int kill(pid_t pid,int sig);
int raise(int sig);
unisigned int alarm(unsigned int seconds);

kill系统调用负责向进程发送信号sig.
如果pid是正数,那么向信号sig被发送到进程pid.
如果pid等于0,那么信号sig被发送到所以和pid进程在同一个进程组的进程
如果pid等于-1,那么信号发给所有的进程表中的进程,除了最大的哪个进程号.
如果pid由于-1,和0一样,只是发送进程组是-pid.
我们用最多的是第一个情况.还记得我们在守护进程那一节的例子吗?我们那个时候用这个函数杀死了父进程守护进程的创建
raise系统调用向自己发送一个sig信号.我们可以用上面那个函数来实现这个功能的.
alarm函数和时间有点关系了,这个函数可以在seconds秒后向自己发送一个SIGALRM信号. 下面这个函数会有什么结果呢?

#include

main()
{
unsigned int i;
alarm(1);
for(i=0;1;i++)
printf("I=%d",i);
}
SIGALRM的缺省操作是结束进程,所以程序在1秒之后结束,你可以看看你的最后I值为多少,来比较一下大家的系统性能差异(我的是2232).

2。信号操作 有时候我们希望进程正确的执行,而不想进程受到信号的影响,比如我们希望上面那个程序在1秒钟之后不结束.这个时候我们就要进行信号的操作了.
信号操作最常用的方法是信号屏蔽.信号屏蔽要用到下面的几个函数.

#include

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
int sigismember(sigset_t *set,int signo);
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);

sigemptyset函数初始化信号集合set,将set设置为空.sigfillset也初始化信号集合,只是将信号集合设置为所有信号的集合. sigaddset将信号signo加入到信号集合之中,sigdelset将信号从信号集合中删除.sigismember查询信号是否在信号集合之 中.
sigprocmask是最为关键的一个函数.在使用之前要先设置好信号集合set.这个函数的作用是将指定的信号集合set加入到进程的信号阻塞集合之中去,如果提供了oset那么当前的进程信号阻塞集合将会保存在oset里面.参数how决定函数的操作方式.
SIG_BLOCK:增加一个信号集合到当前进程的阻塞集合之中.
SIG_UNBLOCK:从当前的阻塞集合之中删除一个信号集合.
SIG_SETMASK:将当前的信号集合设置为信号阻塞集合.
以一个实例来解释使用这几个函数.

#include
#include
#include
#include

int main(int argc,char **argv)
{
double y;
sigset_t intmask;
int i,repeat_factor;

if(argc!=2)
{
fprintf(stderr,"Usage:%s repeat_factor/n/a",argv[0]);
exit(1);
}

if((repeat_factor=atoi(argv[1]))<1)repeat_factor=10;
sigemptyset(&intmask); /* 将信号集合设置为空 */
sigaddset(&intmask,SIGINT); /* 加入中断 Ctrl+C 信号*/
while(1)
{
/*阻塞信号,我们不希望保存原来的集合所以参数为NULL*/
sigprocmask(SIG_BLOCK,&intmask,NULL);
fprintf(stderr,"SIGINT signal blocked/n");
for(i=0;i fprintf(stderr,"Blocked calculation is finished/n");
/* 取消阻塞 */
sigprocmask(SIG_UNBLOCK,&intmask,NULL);
fprintf(stderr,"SIGINT signal unblocked/n");
for(i=0;i fprintf(stderr,"Unblocked calculation is finished/n");
}
exit(0);
}

程序在运行的时候我们要使用Ctrl+C来结束.如果我们在第一计算的时候发出SIGINT信号,由于信号已经屏蔽了,所以程序没有反映.只有到 信号被取消阻塞的时候程序才会结束. 注意我们只要发出一次SIGINT信号就可以了,因为信号屏蔽只是将信号加入到信号阻塞集合之中,并没有丢弃这个信号.一旦信号屏蔽取消了,这个信号就会 发生作用.
有时候我们希望对信号作出及时的反映的,比如当拥护按下Ctrl+C时,我们不想什么事情也不做,我们想告诉用户你的这个操作不好,请不要重试,而不是什么反映也没有的. 这个时候我们要用到sigaction函数.
#include

int sigaction(int signo,const struct sigaction *act,
struct sigaction *oact);

struct sigaction {
void (*sa_handler)(int signo);
void (*sa_sigaction)(int siginfo_t *info,void *act);
sigset_t sa_mask;
int sa_flags;
void (*sa_restore)(void);
}

这个函数和结构看起来是不是有点恐怖呢.不要被这个吓着了,其实这个函数的使用相当简单的.我们先解释一下各个参数的含义. signo很简单就是我们要处理的信号了,可以是任何的合法的信号.有两个信号不能够使用(SIGKILL和SIGSTOP). act包含我们要对这个信号进行如何处理的信息.oact更简单了就是以前对这个函数的处理信息了,主要用来保存信息的,一般用NULL就OK了.
信号结构有点复杂.不要紧我们慢慢的学习.
sa_handler是一个函数型指针,这个指针指向一个函数,这个函数有一个参数.这个函数就是我们要进行的信号操作的函数. sa_sigaction,sa_restore和sa_handler差不多的,只是参数不同罢了.这两个元素我们很少使用,就不管了.
sa_flags用来设置信号操作的各个情况.一般设置为0好了.sa_mask我们已经学习过了
在使用的时候我们用sa_handler指向我们的一个信号操作函数,就可以了.sa_handler有两个特殊的值:SIG_DEL和SIG_IGN.SIG_DEL是使用缺省的信号操作函数,而SIG_IGN是使用忽略该信号的操作函数.
这个函数复杂,我们使用一个实例来说明.下面这个函数可以捕捉用户的CTRL+C信号.并输出一个提示语句.

#include
#include
#include
#include
#include

#define PROMPT "你想终止程序吗?"

char *prompt=PROMPT;

void ctrl_c_op(int signo)
{
write(STDERR_FILENO,prompt,strlen(prompt));
}

int main()
{
struct sigaction act;

act.sa_handler=ctrl_c_op;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
if(sigaction(SIGINT,&act,NULL)<0)
{
fprintf(stderr,"Install Signal Action Error:%s/n/a",strerror(errno));
exit(1);
}
while(1);
}

在上面程序的信号操作函数之中,我们使用了write函数而没有使用fprintf函数.是因为我们要考虑到下面这种情况.如果我们在信号操作的时候又有 一个信号发生,那么程序该如何运行呢? 为了处理在信号处理函数运行的时候信号的发生,我们需要设置sa_mask成员. 我们将我们要屏蔽的信号添加到sa_mask结构当中去,这样这些函数在信号处理的时候就会被屏蔽掉的.
3。其它信号函数 由于信号的操作和处理比较复杂,我们再介绍几个信号操作函数.

#include
#include

int pause(void);
int sigsuspend(const sigset_t *sigmask);

pause函数很简单,就是挂起进程直到一个信号发生了.而sigsuspend也是挂起进程只是在调用的时候用sigmask取代当前的信号阻塞集合.
#include

int sigsetjmp(sigjmp_buf env,int val);
void siglongjmp(sigjmp_buf env,int val);

还记得goto函数或者是setjmp和longjmp函数吗.这两个信号跳转函数也可以实现程序的跳转让我们可以从函数之中跳转到我们需要的地方.
由于上面几个函数,我们很少遇到,所以只是说明了一下,详细情况请查看联机帮助.
4。一个实例 还记得我们在守护进程创建的哪个程序吗?守护进程在这里我们把那个程序加强一下. 下面这个程序会在也可以检查用户的邮件.不过提供了一个开关,如果用户不想程序提示有新的邮件到来,可以向程序发送SIGUSR2信号,如果想程序提供提 示可以发送SIGUSR1信号.


#include
#include
#include
#include
#include
#include
#include

#include
#include

/* Linux 的默任个人的邮箱地址是 /var/spool/mail/ */

#define MAIL_DIR "/var/spool/mail/"

/* 睡眠10秒钟 */

#define SLEEP_TIME 10
#define MAX_FILENAME 255

unsigned char notifyflag=1;

long get_file_size(const char *filename)
{
struct stat buf;

if(stat(filename,&;buf)==-1)
{
if(errno==ENOENT)return 0;
else return -1;
}
return (long)buf.st_size;
}

void send_mail_notify(void)
{
fprintf(stderr,"New mail has arrived/007/n");
}

void turn_on_notify(int signo)
{
notifyflag=1;
}

void turn_off_notify(int signo)
{
notifyflag=0;
}

int check_mail(const char *filename)
{
long old_mail_size,new_mail_size;
sigset_t blockset,emptyset;

sigemptyset(&;blockset);
sigemptyset(&;emptyset);
sigaddset(&;blockset,SIGUSR1);
sigaddset(&;blockset,SIGUSR2);

old_mail_size=get_file_size(filename);
if(old_mail_size<0)return 1;
if(old_mail_size>0) send_mail_notify();
sleep(SLEEP_TIME);

while(1)
{
if(sigprocmask(SIG_BLOCK,&;blockset,NULL)<0) return 1;
while(notifyflag==0)sigsuspend(&;emptyset);
if(sigprocmask(SIG_SETMASK,&;emptyset,NULL)<0) return 1;
new_mail_size=get_file_size(filename);
if(new_mail_size>old_mail_size)send_mail_notify;
old_mail_size=new_mail_size;
sleep(SLEEP_TIME);
}
}

int main(void)
{
char mailfile[MAX_FILENAME];
struct sigaction newact;
struct passwd *pw;

if((pw=getpwuid(getuid()))==NULL)
{
fprintf(stderr,"Get Login Name Error:%s/n/a",strerror(errno));
exit(1);
}
strcpy(mailfile,MAIL_DIR);
strcat(mailfile,pw->pw_name);
newact.sa_handler=turn_on_notify;
newact.sa_flags=0;
sigemptyset(&;newact.sa_mask);
sigaddset(&;newact.sa_mask,SIGUSR1);
sigaddset(&;newact.sa_mask,SIGUSR2);
if(sigaction(SIGUSR1,&;newact,NULL)<0)
fprintf(stderr,"Turn On Error:%s/n/a",strerror(errno));
newact.sa_handler=turn_off_notify;
if(sigaction(SIGUSR1,&;newact,NULL)<0)
fprintf(stderr,"Turn Off Error:%s/n/a",strerror(errno));
check_mail(mailfile);
exit(0);
}

信号操作是一件非常复杂的事情,比我们想象之中的复杂程度还要复杂,如果你想彻底的弄清楚信号操作的各个问题,那么除了大量的练习以外还要多看联机手册.不过如果我们只是一般的使用的话,有了上面的几个函数也就差不多了. 我们就介绍到这里了.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 1.1均匀分布的随机数 第一章 数字信号的产生 1.2正态分布的随机数 1.3指数分布的随机数 1.4拉普拉斯(Laplace)分布的随机数 1.5瑞利(Rayleigh)分布的随机数 1.6对数正态分布的随机数 第一篇 常用数字信号的产生 1.7柯西(Cauchy)分布的随机数 1.8韦伯(Weibull)分布的随机数 1.9爱尔朗(Erlang)分布的随机数 1.10贝努里(Bernoulli)分布的随机数 1.11贝努里—高斯分布的随机数 1.12二项式分布的随机数 1.13泊松(Poisson)分布的随机数 1.14ARMA(p,q)模型数据的产生 1.15含有高斯白噪声的正弦组合信号的产生 1.16解析信号的产生 1.1离散傅立叶变换 第一章 快速傅立叶变换 1.2快速傅立叶变换 1.3基4快速傅立叶变换 1.4分裂基快速傅立叶变换 1.5实序列快速傅立叶变换(一) 1.6实序列快速傅立叶变换(二) 1.7用一个N点复序列的FFT同时计算两个N点实序列离散傅立叶变换 1.8共轭对称序列的快速傅立叶反变换 1.9素因子快速傅立叶变换 1.10ChirpZ—变换算法 2.1快速哈特莱(Hartley)变换 第二章 快速离散正交变换 2.2基4快速哈特莱(Hartley)变换 第二篇 数字信号处理 2.3分裂基快速哈特莱(Hartley)变换 2.4快速离散余弦变换 2.5快速离散余弦反变换 2.6N=8点快速离散余弦变换 2.7N=8点快速离散余弦反变换 2.8快速离散正弦变换 2.9快速沃尔什(Walsh)变换 2.10快速希尔伯特变换(一) 2.11快速希尔伯特变换(二) 3.1快速卷积 第三章 快速卷积与相关 3.2长序列的快速卷积 3.3特别长序列的快速卷积 3.4快速相关 4.1数字滤波器的频率响应 第四章 数字滤波器的时域和频域响应 4.2级联型数字滤波器的频率响应 4.3数字滤波器的时域响应 4.4直接型IIR数字滤波(一) 4.5直接型IIR数字滤波(二) 4.6级联型IIR数字滤波 4.7并联型IIR数字滤波 5.1巴特沃兹和切比雪夫数字滤波器的设计 第五章 IIR数字滤波器的设计 5.2任意幅度IIR数字滤波器的优化设计 6.1窗函数方法 第六章 FIR数字滤波器的设计 6.2频域最小误差平方设计 6.3切比雪夫逼近方法 1.1功率谱估计的周期图方法 第一章 经典谱估计 1.2功率谱估计的相关方法 2.1求解一般托布利兹方程组的莱文森算法 第二章 现代谱估计 2.2求解对称正定方程组的乔里斯基算法 2.3求解尤利—沃克方程的莱文森—德宾算法 2.4计算ARMA模型的功率谱密度 2.5尤利—沃克谱估计算法 2.6协方差谱估计算法 2.7Burg谱估计算法 2.8最大似然谱估计算法 3.1维格纳(Wigner)分布 第三章 时—频分析 3.2离散小波变换 4.1维纳(Wiener)数字滤波 第四章 随机信号的数字滤波 4.2卡尔曼(Kalman)数字滤波 4.3最小均方(LMS)自适应数字滤波 4.4归一化LMS自适应数字滤波 4.5递推最小二乘(RLS)自适应数字滤波 1.1图像读取、存储与显示 第四篇 数字图像处理 第一章 图像基本运算 1.2图像旋转 1.3图像灰度级直方图的计算 1.4图像二值化的固定阀值法 1.5图像二值化的自适应阀值法 第三篇 随机数字信号处理 2.1图像直方图均衡 第二章 图像增强 2.2中值滤波 2.3图像锐化 2.4图像平滑 3.1Roberts算子边缘检测 第三章 图像边缘检测 3.2拉普拉斯算子边缘检测 3.3Sobel算子边缘检测 3.4Robinson算子边缘检测 3.5Kirsch算子边缘检测 3.6Prewitt算子边缘检测 4.1Hilditch细化算法 第四章 图像细化 4.2Pavlidis细化算法 4.3Rosenfeld细化算法 1.1多层感知器神经网络 第一章 神经网络模型 1.2离散Hopfield神经网络 1.3连续Hopfield神经网络 第五篇 人工神经网络 1.4Tank-Hopfield线性规划神经网络
### 回答1: "linuxc语言编程入门.pdf" 是一本在网盘上提供的适用于Linux系统下的C语言编程入门教程的电子书。它可能包含了C语言基础、语法、数据类型、指针、数组、字符串等内容,并且以适合初学者的方式进行讲解。 通过这本书,你可以学习如何在Linux系统下进行C语言编程Linux是一个非常流行且强大的操作系统,许多开发者选择使用它来开发软件。C语言是一种底层语言,功能强大且广泛应用于各种领域,如系统编程、嵌入式开发和网络编程等。因此,学习如何在Linux下进行C语言编程将为你的编程生涯打下坚实的基础。 在学习这本教程时,你可以期望了解C语言的基本概念和语法,掌握如何使用它编写简单的程序,并逐步深入了解更高级的概念,如函数、结构体和文件操作等。这本教程可能会提供一些示例和练习,以帮助你更好地理解和应用所学内容。 值得一提的是,这本书在网盘上提供,意味着你可以免费获取它,而不需要花费额外的费用。你只需有一个可用的网络连接,并在网盘上搜索并下载这本书即可开始你的学习之旅。 总而言之,"linuxc语言编程入门.pdf" 是一个适用于Linux系统的C语言入门教程,它将为初学者提供学习C语言编程的基础知识,并帮助他们在Linux系统上开始编写简单的C程序。这本书的免费提供使得获取它变得容易,只需搜索并下载即可开始学习。 ### 回答2: linuxc语言编程入门.pdf 网盘是一个在线存储和分享文件的平台,专门提供给用户上传、下载和传输PDF格式的C语言编程入门教程。 在linux系统下进行C语言编程是一种常见的选择,因为linux系统本身就内置了gcc编译器,可以直接进行C语言程序的编译和运行。而linuxc语言编程入门.pdf 网盘提供了对应的教程,方便初学者快速入门和学习C语言编程。 使用linuxc语言编程入门.pdf 网盘,可以从以下几个方面获得帮助和资源: 1. 学习资料:网盘上提供了C语言编程的入门教程,用户可以下载该PDF文件,通过阅读学习基本的C语言语法、数据类型、控制结构等知识。这些教程通常结构清晰、易于理解,适合初学者入门。 2. 代码示例:网盘上可能还提供了一些C语言编程的代码示例,用户可以通过下载这些示例代码,实践理论知识,加深对C语言编程的理解。这些示例代码可能包括了一些常见的编程练习,能够帮助用户掌握C语言的基本语法和常用函数。 3. 讨论和交流:网盘上往往有一个交流平台,用户可以在这个平台上发布问题、交流心得、分享经验等。通过与其他初学者或有经验的程序员的交流,用户可以互相学习,获取更多关于C语言编程的知识和技巧。 总之,linuxc语言编程入门.pdf 网盘是一个提供C语言编程学习资源的平台,可以帮助初学者系统地学习和掌握C语言编程的基础知识。通过下载相关教程和代码示例,以及参与交流和讨论,用户可以逐步提升自己的C语言编程能力。 ### 回答3: linuxc语言编程入门.pdf是一本介绍在Linux系统下使用C语言进行编程的教程。该教程可以通过网盘进行下载和分享。 在网盘中,用户可以搜索并找到该教程,然后选择下载到本地或者在线阅读。用户可以通过网盘提供的下载链接将该教程保存到自己的电脑或其他设备上,方便随时学习和查阅。 该教程的内容包括C语言的基础知识、语法、数据类型、运算符、流程控制语句等等,适合初学者入门使用。同时,还介绍了在Linux系统中使用C语言进行开发的一些常见工具和技巧,如gcc编译器、Makefile使用、调试工具等等。 通过学习该教程,用户可以了解到C语言Linux系统中的应用和开发环境的搭建方式。同时,也可以学习到如何使用C语言编写简单的程序和应用,如计算器、猜数字游戏等等。 总而言之,linuxc语言编程入门.pdf是一本在Linux系统中学习和使用C语言编程的入门教程,用户可以通过网盘进行下载和学习。这本教程对于有志于学习C语言编程的初学者来说,是一个很好的学习资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值