`
tomotoboy
  • 浏览: 162457 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

进程间通信——信号

阅读更多
信号类型
信号类型在Trap命令详解中有详细的介绍

信号捕捉
示列程序实现对SIGINT的捕捉
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
int catch(int sig);
int main(void)
{
        signal(SIGINT,catch);  /* 将SIGINT 信号与catch函数关联 */
         printf("xixi\n");
         sleep(10);
         printf("end\n");
         return;
}
int catch(int sig)
{
         printf("Catch succeed!\n");
         return 1;
}


执行过程:
pro_1.c: In function `main':
pro_1.c:7: warning: passing arg 2 of `signal' from incompatible pointer type
/home/l/g/tomotoboy/signal >pro_1
xixi
^CCatch succeed!
end


信号与系统调用的关系
当一个进程正在执行一个系统调用时,如果向该进程发送一个信号,那么对于大多数系统调用来说,这个信号在系统调用完成之前将不起作用,因为这些系统调用不能被信号打断。但是有少数几个系统调用能被信号打断,例如:wait(),pause()以及对慢速设备(终端、打印机等)的 read()、write()、open()等。如果一个系统调用被打断,它就返回-1,并将errno设为 EINTR。可以用下列代码来处理这种情况:
if (wirte(tfd,buf,SIZE)<0) {
  if (errno==EINTR) {
  warn(“ Write interrupted.” );
  …
  …
  }
}



信号的复位
在 Linux 中,当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。下面的程序演示了这一点:
#include <signal.h>
int interrupt()
{
     printf(" Interrupt called\n" );
     sleep(3);
     printf(" Interrupt Func Ended.\n" );
}
main()
{
     signal(SIGINT,interrupt);
     printf(" Interrupt set for SIGINT\n" );
     sleep(10);
     printf(" Program NORMAL ended.\n" );
     return;
}

执行过程:
/home/l/g/tomotoboy/signal >pro_2
Interrupt set for SIGINT
^C Interrupt called
^C
/home/l/g/tomotoboy/signal >pro_2
Interrupt set for SIGINT
^C Interrupt called
Interrupt Func Ended.Program NORMAL ended.

问题:当我第二次按下Ctrl+C时,程序直接终止,现在还在找原因
但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断:
#include <signal.h>
int interrupt()
{
printf(" Interrupt called\n" );
sleep(3);
printf(" Interrupt Func Ended.\n" );
}
int catchquit()
{
printf(" Quit called\n" );
sleep(3);
printf(" Quit ended.\n" );
}
main()
{
   signal(SIGINT,interrupt);
   signal(SIGQUIT,catchquit);
    printf(" Interrupt set for SIGINT\n" );
    sleep(10);
    printf(" Program NORMAL ended.\n" );
    return;
}
执行这个程序的结果如下:
/home/l/g/tomotoboy/signal >gcc pro_3.c -o pro_3
pro_3.c: In function `main':
pro_3.c:16: warning: passing arg 2 of `signal' from incompatible pointer type
pro_3.c:17: warning: passing arg 2 of `signal' from incompatible pointer type
/home/l/g/tomotoboy/signal >pro_3
 Interrupt set for SIGINT
^C Interrupt called
^\ Quit called
 Quit ended.
 Interrupt Func Ended.
 Program NORMAL ended.

还要注意的是,在 Linux 系统中同种信号是不能积累的。而且如果两个信号同时产生,系统并不保证进程接收它们的次序。以上的两个缺点影响了信号作为进程通信手段的可靠性,因为一个进程不能保证它发出的信号不被丢失。当某个信号未被处理的时候,如果对该信号执行 signal调用,那么该信号将被注销。

在进程间发送信号
一个进程通过对 signal()的调用来处理其它进程发送来的信号。同时,一个进程也可以向其它的进程发送信号。这一操作是由系统调用 kill()来完成的。 kill()在 linux 系统库 signal.h中的函数声明如下:
int kill(pid_t pid, int sig);

参数 pid 指定了信号发送的对象进程:它可以是某个进程的进程标识符(pid),也可以是以下的值:
  • 如果 pid 为零,则信号被发送到当前进程所在的进程组的所有进程。
  • 如果 pid 为-1,则信号按进程标识符从高到低的顺序发送给全部的进程(这个过程受到当前进程本身权限的限制);
  • 如果 pid 小于-1,则信号被发送给标识符为 pid 绝对值的进程组里的所有进程。
  • 参数 sig 指定发送的信号类型。它可以是任何有效的信号。

需要说明的是,一个进程并不是向任何进程均能发送信号的,这里有一个限制,就是普通用户的进程只能向具有与其相同的用户标识符的进程发送信号。也就是说,一个用户的进程不能向另一个用户的进程发送信号。只有 root 用户的进程能够给任何线程发送信号。

由于调用 kill()的进程需要直到信号发往的进程的标识符,所以这种信号的发送通常只在关系密切的进程之间进行,比如父子进程之间。
#include <signal.h>
int ntimes=0;
main(){

int pid,ppid;
int p_action(),c_action();
signal(SIGUSR1,p_action);
switch(pid=fork()){
case -1:
        perror("sychro");
        exit(1);
case 0:
        signal(SIGUSR1,c_action);
                ppid=getppid();
        for(;;){
                sleep(1);
                kill(ppid,SIGUSR1);
                pause();
        }
        break;

default:
        for(;;){
                pause();
                sleep(1);
                kill(pid,SIGUSR1);

        }
}
}
p_action()
{
        printf("Patent caught signal #%d\n",++ntimes);
}
c_action()
{
        printf("Child caught signal #%d\n",++ntimes);
}
执行过程如下:
/home/l/g/tomotoboy/signal >gcc pro_4.c -o pro_4
pro_4.c: In function `main':
pro_4.c:6: warning: passing arg 2 of `signal' from incompatible pointer type
pro_4.c:12: warning: passing arg 2 of `signal' from incompatible pointer type
/home/l/g/tomotoboy/signal >pro_4
Patent caught signal #1
Child caught signal #1
User Signal 1

问题:本来按照程序的意图父、子应该循环交替执行,然而各自却只执行了一次就结束了
kill命令用于向一个运行进程发送信号,它发送的信号默认为 SIGTERM,但是也可以指定为其它信号。我们可以直接用信号的号码来指定 kill 命令所发送信号之类型,也可以用符号名指定。比如可以用下面的命令来完成向进程标识符为 1234 的进程发送SIGINT 信号:
kill – s SIGINT 1234


系统调用 alarm()和 pause()
1.系统调用 alarm()
alarm()是一个简单而有用的系统调用,它可以建立一个进程的报警时钟,在时钟定时器到时的时候,用信号向程序报告。alarm()系统调用在 Linux 系统函数库 unistd.h中的函数
声明如下:
unsigned int alarm(unsigned int seconds);

下面这个程序使用上述方法来强制用户作出回答。在其中包括一个 quickreply()函数,它有一个参数 prompt,它是一个指向提示字符串的指针。quickreply 的返回值也是一个指针。它指向含有输入行信息的字符串。这个例行程序在试作五次之后,如果仍未得到输入信息,就返回一个 null 指针。每当quickreply 要提醒用户时,它就向终端发送 ASCII 码 007,这会使终端响铃。
#include <stdio.h>
#include <signal.h>
#define TIMEOUT 5
#define MAXTRIES 5
#define LINESIZE 100
#define BELL '\007'
#define TRUE 1
#define FALSE 0
static int time_out;/*判断超时是否已经发生的标志 */
static char inputline[LINESIZE];
char* quickreply (char* prompt);
main()
{
	printf("%s\n",quickreply("Input"));
}
char* quickreply (char* prompt)
{
	int (*was)(),catch(),ntries;
	char* answer;
	/*设定捕捉SIGALRM 的的关联并保存原有关联*/
	was=signal(SIGALRM,catch);
	for (ntries=0;ntries<MAXTRIES;ntries++)
	{
		time_out=FALSE;
		printf("\n%s>",prompt);
		/* 设定定时器 */
		alarm(TIMEOUT);
		/* 获取输入 */
		answer=gets(inputline);
		/* 关闭定时器 */
		alarm(0);
		if (!time_out)
			break;
	}
	/*恢复原有的SIGALRM 关联 */
	signal(SIGALRM,was);
	return (time_out?((char*) 0):answer);
}
/*SIGALRM 信号处理函数*/
catch()
{
	/*设定超时标志*/
	time_out=TRUE;
	/* 响铃警告 */
	putchar(BELL);
}

执行结果:
/home/l/g/tomotoboy/signal >gcc pro_5.c -o pro_5
pro_5.c: In function `quickreply':
pro_5.c:20: warning: passing arg 2 of `signal' from incompatible pointer type
pro_5.c:20: warning: assignment from incompatible pointer type
pro_5.c:31: warning: passing arg 2 of `signal' from incompatible pointer type
/home/l/g/tomotoboy/signal >pro_5

Input>
Input>Alarm Clock
/home/l/g/tomotoboy/signal >pro_5

Input>hello
hello
/home/l/g/tomotoboy/signal >pro_5

Input>
Input>Alarm Clock
/home/l/g/tomotoboy/signal >

不知道怎么回事,今天这几个程序都没有循环起来,信号也只是发了一次,原因查找当中……

2.系统调用 pause()
系统调用 pause()能使调用进程暂停执行,直至接收到某种信号为止。pause()在 Linux系统函数库 unistd.h中的函数声明如下:
int pause(void);
该调用没有任何的参数。它的返回始终是 -1 ,此时 errno 被设置为ERESTARTNOHAND。


参考资料:
《linux网络编程》李卓恒等译
分享到:
评论

相关推荐

    linux进程间通信——信号机制

    对linux信号机制的详细阐述,包括signal,sigaction等函数的用法,并配以实例,通俗易懂,适合初学者阅读。。。

    实验一 进程通信——管道和信号实验报告.doc

    3.(3)进程间信号通信 4.(4)进程的管道通信 编写程序,创建两个子进程。当此程序运行时,系统中有一个父进程和两个子进程。父进程在屏幕上显示“Parent”,子进程分别在屏幕上显示“Child1”和“Child2”。 ...

    linux系统进程间通信——共享内存(System V版本)

    之前用过Prosix版本的共享内存和信号量,一直没有实践System V版本的,主要是因为其信号量集的概念操作有些复杂,今天试着写一个SV版本的共享内存进程间通信,使用信号量同步。程序提供了几个简单的用于操作SV版本...

    详解Linux进程间通信——使用信号量

    主要介绍了详解Linux进程间通信——使用信号量,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    嵌入式操作系统实验报告

    河北工业大学《嵌入式操作系统》实验报告 实验一 Linux下C编程 实验二 搭建NFS服务器 实验三 守护进程 实验四 进程间通信——...实验五 进程间通信——信号机制 实验六 进程间通信——共享内存 综合实验——课程考核

    进程同步——信号量机制

    关于信号量的文章,生产者消费者问题与读者写者问题---信号量机制,PV操作——进程同步的信号量问题,利用信号机制实现的 父子进程同步,嵌入式linux的学习笔记-进程间通信的信号与信号集(四)1)进程的同步与互斥 ...

    进程间通信之套接字( socket )——完整代码

    进程间通信之套接字( socket ) 网络间通信 七种进程间通信方式: 一.无名管道( pipe ) 二.有名管道( fifo ) 三.共享内存 ( shared memory ) 四.信号 ( sinal ) 五.消息队列 ( message queue ) 六.信号量 ( ...

    进程间通信之消息队列 ( message queue )——完整代码

    进程间通信之消息队列 ( message queue ) 消息队列是消息的链表,具有特定的格式,并由消息队列标识符标识. 七种进程间通信方式: 一.无名管道( pipe ) 二.有名管道( fifo ) 三.共享内存 ( shared memory ) 四....

    Linux进程间通信--使用信号

    本篇文章主要介绍了Linux进程间通信--使用信号的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧

    详解Linux进程间通信——使用共享内存

    进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问...

    Linux 下进程间通信实例

    Linux 下进程间通信实例之一——共享内存 使用了信号量用于进程间的同步

    进程间通信机制的分析与比较

    进程在核心的协调下进行相互间的通讯机制——管道,信号量,消息队列。

    《UNIX网络编程 第2版. 第2卷, 进程间通信(中文版)》(W·Richard Stevens[美] 著)

    良好的进程间通信(IPC)机制是提高UNIX程序性能的关键。本书全面深入地讲解了各种进程间通信形式,包括消息传递、同步、共享内存及远程调用(RPC)。书中包含了大量经过优化的源代码,帮助读者加深理解。这些源代码...

    《Visual C++范例大全》随书光盘 第十一章

    第11章 实例257——使用Win32 API创建、销毁线程(控制进度条) 实例258——创建MFC用户界面线程 实例259——创建MFC工作者线程,进行耗时计算 实例260——设置线程的... 实例277——通过消息机制实现进程间的通信

    Linux通过匿名管道进行进程间通信

    这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据。 一、什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号“|”来使用...

    信号中断处理示例代码

    Linux系统编程——进程间通信:信号中断处理,相关教程链接如下: http://blog.csdn.net/tennysonsky/article/details/46010303

    linux源代码分析——消息管理

    在操作系统中,有些进程存在着相互制约的关系,这些制约关系来源于并行... 这种机制就叫做进程间通信,或IPC.在linux 中支持UNIX SYSTEM V 的三种通信机制: 消息队列, 信号量和共享内存. 现就消息队列这种机制进行分析.

    编程模拟多进程共享临界资源

    学校按排做的课程设计——编程模拟多进程共享临界资源! 设计内容 要求产生3个进程: 1、两个进程模拟需要进入临界区的...4、进程间通信可以采用信号、消息传递、管道或网络通信方式。 内附有:代码文件和设计文档。。

    《Linux C编程实战》.(童永清).pdf带标签

    《Linux C编程实战》内容翔实,主要包括:Linux系统下C语言及其编程环境的介绍,系统编程的所有主题——文件和目录、进程、线程、信号、进程间通信、网络编程和图形界面编程、出错处理、库的创建与使用、编写安全的...

Global site tag (gtag.js) - Google Analytics