Linux环境编程之信号(一):信号基本概述

引言

假如在后台运行一个可执行程序./a.out,如果想终止该程序,通常会按下Ctrl-C,从而产生一个中断,其实这个过程的实现就是通过信号完成的。信号是软件中断,它提供了一种处理异步事件的方法。

(一)

每个信号都有一个名字,这些名字都以三个字符SIG开头。例如SIGALARM是闹钟信号,当由alarm函数设置的计时器超时后产生此信号。Linux除支持31种不同信号外,还支持应用程序额外定义信号。信号定义在<bits/signum.h>中,也可以通过命令kill -l查看。

(二)信号的产生

信号是如何产生的呢,下列方式均可产生信号:

1、当用户按某些终端键时,引发终端产生的信号。

2、硬件异常产生信号:除数为0、无效的内存引用等等。

3、进程调用kill(2)函数可将信号发送给另一个进程或进程组。

4、用户可用kill(1)命令将信号发送给其他进程。

5、当检测到某种软件条件已经发生,并应将其通知有关进程时也产生信号。

(三)信号的处理

进程不能简单地测试一个变量来判别是否出现了一个信号,而是必须告诉内核“在此信号出现时,请执行下列操作”。信号的处理包括三种方式:忽略信号、捕捉信号、执行系统默认动作。

注意:

1、大多数信号都可以使用忽略信号的方式进行处理,但对于SIGKILL和SIGSTOP信号则不能忽略,因为它们向超级用户提供了使进程终止或停止的可靠方法。

2、为了捕捉信号,要通知内核在某种信号发生时调用一个用户函数。SIGKILL和SIGSTOP信号不能被捕捉。

3、大多数信号的系统默认动作是终止进程。

(三)signal函数示例

信号机制最简单的接口就是signal函数。原型如下:

#include <signal.h>

void (*signal(int signo, void (*func)(int)))(int);

signo是以SIG三个字母开头的信号名。func的值是常量SIG_IGN(忽略此信号)、常量SIG_DFL(系统默认动作)或当接到此信号后要调用的函数地址(信号发生时,调用该函数,即信号处理程序)。

/*
 *File Name:signal.c
 *Author   : libing
 *Mail     : [email protected]
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

static void sig_usr(int);

int
main(void)
{
	if(signal(SIGUSR1, sig_usr) == SIG_ERR)//signal函数
		printf("can‘t catch SIGUSR1");
	if(signal(SIGUSR2, sig_usr) == SIG_ERR)
		printf("can‘t catch SIGUSR2");
	for(;;)
		pause(); /*go to sleep, waiting for signal*/
	return 0;
}

static void
sig_usr(int signo)
{
	if(signo == SIGUSR1)
		printf("received SIGUSR1.\n");
	else if(signo == SIGUSR2)
		printf("received SIGUSR2.\n");
	else
		printf("received signal %d\n", signo);
}

程序测试:

编译:gcc signal.c -o signal
运行:./signal &
测试:kill -USR1 8522
kill -USR2 8522
kill 8522

注意:kill命令和kill函数只是将一个信号送给一个进程或进程组。信号是否终止进程则取决于信号的类型,以及进程是否安排了捕捉该信号。

Linux环境编程之信号(一):信号基本概述

时间: 2024-08-24 07:17:47

Linux环境编程之信号(一):信号基本概述的相关文章

Linux环境编程之信号(三):一些信号函数

(一)kill和raise函数 kill函数将信号发送给进程或进程组.raise函数则允许进程自身发送信号. #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); int raise(int  signo);  //返回值:若成功则返回0,若出错则返回-1. 参数:pid参数有4种情况:1.pid > 0 将信号发送给进程为pid的进程.2.pid == 0 将该信号发送给与发送进程属

Linux环境编程之信号(二):不可靠信号、中断的系统调用、可重入函数

(一)不可靠信号 对前面说的信号,是不可靠的,不可靠指的是信号可能会丢失:一个信号发生了,但进程却可能一直不知道这一点.另外,进程对信号的控制能力有限,只能捕捉信号或忽略它.有时用户希望通知内核阻塞一个信号:不要忽略它,在其发生时记住它,然后在进程做好准备时再通知它.这种阻塞信号的能力并不具备. 之前的版本中村咋一个问题:在进程每次接到信号对其进行处理时,随即将该信号动作复位为默认值.另一个问题是,在进程不希望某种信号发生时,它不能关闭该信号.进程能做的一切就是忽略该信号. (二)中断的系统调用

[linux环境编程] 信号的基本概念与操作函数

[linux环境编程] 信号的基本概念与操作函数 一.基本的概念 1.中断的基本概念 中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序. 而在Linux中通常分为外部中断(又叫硬件中断)和内部中断(又叫异常). 硬中断:来自硬件设备的中断 软中断:来自其它程序的中断 2.信号的基本概念 信号是软件中断,提供了一种处理异步事件的方法,可以把他看作是进

Linux环境编程之进程(一):main函数调用、进程终止以及命令行参数和环境表

(一)main函数调用 main函数作为程序运行时的入口函数,它是如何被调用的呢?首先必须清楚一点,main函数也是一个函数,它只有被调用才能够执行.其实,在执行可执行程序时,在调用main函数之前,内核会先调用一个特殊的启动例程,将此启动例程作为可执行程序的起始地址.启动例程是如何作为可执行程序的起始地址的?这是由链接编译器设置的,而链接编译器则是由C编译器(如gcc编译器)调用的.启动例程作为可执行程序的起始地址主要做哪些工作呢?启动例程从内核取得命令行参数和环境变量值,以此来为main函数

Linux环境编程之文件I/O(五):fcntl函数

引言: 对于一个普通的文件,我们可以想到的对它的操作有,读取文件的内容.写数据到文件中,这些都是前面提到的read.write函数的作用.除此之外,还可以获取文件的其他性质,并对这些性质进行修改,比如文件的描述符.文件描述符标记.文件状态标志等等.这些对文件性质的修改就由fcntl函数完成. 函数介绍: #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 参数: fd:

Linux环境编程之文件I/O(三):文件的读写

(一) 当我们打开了一个文件后,一般对文件的操作就是读写.读写函数分别是read.write. #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); 参数: fd:利用open.creat得到的文件描述符. buf:buf是void *类型,用于表示通用指针,此处指所读取到的数据的内存缓冲. count:需要读取的数据量. 返回值:成功执行时,返回所读取的数据的字节数,一般等于或小于所请求读取的数据字节数.若已到文

Linux环境编程之同步(四):Posix信号量

信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语.有三种类型:Posix有名信号量,使用Posix IPC名字标识:Posix基于内存的信号量,存放在共享内存区中:System V信号量,在内核中维护.这三种信号量都可用于进程间或线程间的同步. 图1 由两个进程使用的一个二值信号量 图2 由两个进程使用的一个Posix有名二值信号量 图3 由一个进程内的两个线程共享的基于内存的信号量 一个进程可以在某个信号量上执行的三种操作: 1.创建一个信号量,这要求调用者指定初始值,对

Linux环境编程之高级I/O(一):非阻塞I/O、记录锁

引言:高级I/O包括非阻塞I/O.记录锁.系统V流机制.I/O多路转接(select和poll函数).readv和writev函数以及存储映射I/O. (一)非阻塞I/O 可能会使进程永远阻塞的一类系统调用有: 1.如果某些文件类型的数据并不存在,则读操作可能会使调用者永远阻塞. 2.如果数据不能立即被上述同样类型的文件接受,则写操作也会使调用者永远阻塞. 3.在某种条件发生之前,打开某些类型的文件会阻塞. 4.对已经加上强制记录锁的文件进行读.写. 5.某些ioctl操作. 6.某些进程间通信

Linux环境编程之进程(四):创建新进程、执行程序和进程终止

引言: 对于每个进程,都有一个非负整数表示的唯一进程ID.虽然进程的ID是唯一的,但却是可重用的.系统中有一些专用的进程.如ID为0的进程通常是调度进程,也成交换进程或系统进程(它是内核进程).进程ID为1通常是init进程,它是一个普通的用户进程.一些与进程ID有关的函数: #include <unistd.h> pid_t getpid(void);   //返回值:调用进程的进程ID pit_t getppid(void); //返回值:调用进程的父进程ID uid_t getuid(v