`
tomotoboy
  • 浏览: 166832 次
  • 性别: 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

    【进程间通信:信号通信】 这部分实验中,使用了signal()系统调用来处理键盘上的中断信号(DEL键)。当父进程捕获到中断信号后,通过kill()向两个子进程发送信号,子进程接收到信号后输出相应信息并终止。同时,...

    Linux环境进程间通信 信号灯

    ### Linux环境下的进程间通信——信号灯 #### 一、信号灯概述 信号灯是一种用于进程间通信(IPC)的机制,主要用于协调多个进程对共享资源的访问控制。它可以被视为一种内存中的标志,用来指示资源的可用性。进程...

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

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

    嵌入式操作系统实验报告

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

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

    ### 详解Linux进程间通信——使用信号量 #### 一、什么是信号量 信号量是一种常用的同步机制,用于解决多进程或线程并发访问共享资源时可能出现的竞争条件问题。在多进程环境中,当多个进程尝试同时访问同一个共享...

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

    本实验旨在通过实际操作深入理解进程通信的相关概念和技术,特别是管道和信号这两种进程间通信方式。实验目标具体包括: 1. **加深对进程概念的理解**:通过实践明确进程与程序的区别。 2. **认识并发执行的实质**...

    进程同步——信号量机制

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

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

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

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

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

    高级进程间通信问题——快速排序问题1

    【高级进程间通信问题——快速排序问题1】的实验是一个基于操作系统原理的编程挑战,旨在实现一个多线程或多进程的快速排序算法。这个实验在Ubuntu 18.04.5 LTS环境下进行,采用C/C++编程语言,并且允许使用C++11的...

    Linux进程间通信-信号通信信号发送实例.pdf

    在Linux操作系统中,进程间通信(IPC,Inter-Process Communication)是多个进程间协同工作、交换数据的关键机制。本文将重点讨论其中的一种通信方式——信号通信,并通过具体的信号发送实例来解析其工作原理。 ...

    Linux进程间通信-信号通信定时信号实例.pdf

    在Linux操作系统中,进程间通信(IPC,Inter-Process Communication)是多个进程间相互协作、交换数据的关键机制。本文将详细讲解一种常见的IPC方式——信号(Signal)通信,特别是其中的定时信号(Timed Signal)...

    Linux 多进程及其通信

    文档"Linux进程间通信——使用信号.docx"可能会详细解释如何发送和处理不同类型的信号,以及如何自定义信号处理函数。 2. **信号量(Semaphores)**:信号量是同步原语,用于控制多个进程对共享资源的访问。它们...

    进程间通信经典——银行柜员服务问题

    在IT领域,进程间通信(IPC,Inter-Process Communication)是多进程系统中不同进程之间交换数据的关键技术。尤其在Windows操作系统中,进程间通信扮演着至关重要的角色,使得不同进程能够协同工作,共享资源,解决...

    Linux进程间通信-信号通信实例.pdf

    在Linux操作系统中,进程间通信(IPC,Inter-Process Communication)是多个进程间进行数据交换的重要手段。本文将深入探讨一种常见的IPC方式——信号(Signal)通信,通过几个实例来阐述其基本概念和使用方法。 ...

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

    Linux进程间通信是一种让不同进程之间交换信息或协调工作的方式,而在Linux系统中,信号(Signal)是一种简单但重要的通信机制。本文将深入探讨如何利用信号进行进程间通信。 首先,信号是操作系统用来通知进程发生...

    linux进程通信

    ### Linux进程间通信——信号量详解 #### 一、引言 在Linux系统中,进程间的通信机制是实现多进程程序的关键技术之一。进程间通信(Inter-Process Communication,IPC)使得不同进程能够共享数据、协调操作顺序以及...

Global site tag (gtag.js) - Google Analytics