Linux下signal通信研究(操作系统期中论文之自选题目研究)
2012-01-29 00:14
543 查看
本学期操作系统课期中考核需要写两篇小论文,前篇已经贴过了。今晚无聊,贴出此文,聊以慰籍空虚的心。要下载的朋友,请点击这里。
要求如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/26eceec1f48a118fe0e5ad8472866f77.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/6fa8d1b67891edd320435879b58be31f.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/9da97db90974f56ccb77dd6f6cb46094.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/b1a551b96c8f867a7715e14c1319ec42.gif)
下面是我的论文,由于格式原因,叙述部分直接上图了:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/1269a8b9ffd9264c8fb3043a33c47f51.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/5ff5df8f20e790c8b2b8e3fe7c61b83d.gif)
三、初遇signal
在实验三《Linux进程间通信》---“消息机制的示例程序”中有如下源码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/7f536a30ffe280663d37a11cc094045d.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/db22e94590544cc669933612be922231.gif)
四、Signal通信简介
1、基本知识
软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。第二种方法是忽略某个信号,对该信号不做任何处理,就象未发生过一样。第三种方法是对该信号的处理保留系统的默认值。这种缺省操作,对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。
表头文件: #include<signal.h>
功 能: 设置某一信号的对应动作
函数原型 : void (*signal(intsignum,void(* handler)(int)))(int);
或者:typedef void(*sig_t) ( int );
sig_t signal(int signum,sig_t handler);
参数说明:
第一个参数signum指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。
第二个参数handler描述了与信号关联的动作,它可以取以下三种值:
(1)一个无返回值的函数地址
此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为sig的信号时,就执行handler 所指定的函数。这个函数应有如下形式的定义:
void func(int sig);
sig是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。
(2)SIGIGN
这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号。
(3)SIGDFL
这个符号表示恢复系统对信号的默认处理。
函数说明 :
signal()会依参数signum指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行。当一个信号的信号处理函数执行时,
如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
返回值: 返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
附加说明 :在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,如果要改变此操作请改用sigaction()。
下面的情况可以产生Signal:
1. 按下CTRL+C产生SIGINT
2. 硬件中断,如除0,非法内存访问(SIGSEV)等等
3. Kill函数可以对进程发送Signal
4. Kill命令。实际上是对Kill函数的一个包装
创建driver进程代表司机,seller进程代表售票员。
售票员捕捉SIGINT(代表开车),发SIGUSR1给司机,司机打印("let's go")。
售票员捕捉SIGQUIT(代表停车),发SIGUSR2给司机,司机打印("stop the bus")
司机捕捉SIGTSTP(代表车到总站),发SIGUSR1给售票员,售票员打印("please get off thebus")
Driver.c源代码如下:
Seller.c源代码如下:
运行结果如下:
结果分析:
当在seller进程中按下Ctrl+c(Ctrl+\,Ctrl+z同理)时,seller通过Signal捕获该信号,然后调用sellersigint函数处理该信号。Sellersigint函数通过系统调用kill发送SIGUSR1给driver进程(通过进程ID标识)。在driver进程中,当捕获到SIGUSR1后,掉用函数driversigusr1打印let’s go.
六、总结
到此,通过Signal删除消息队列的原理已经基本明白了。当按下Ctrl+C结束该进程时(Kill同理),当前进程通过Signal捕获该信号然后调用sigend(int) 处理。在sigend(int) 中,通过msgctl(msgid, IPC_RMID, 0)删除相应的消息队列。
以上只是对Signal通信的一些简单的介绍。在Linux操作系统中,许多系统进程通过Signal进行通信此处尚未涉及,有待今后研究。
msgClient源代码:
要求如下:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/26eceec1f48a118fe0e5ad8472866f77.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/6fa8d1b67891edd320435879b58be31f.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/9da97db90974f56ccb77dd6f6cb46094.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/b1a551b96c8f867a7715e14c1319ec42.gif)
下面是我的论文,由于格式原因,叙述部分直接上图了:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/1269a8b9ffd9264c8fb3043a33c47f51.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/5ff5df8f20e790c8b2b8e3fe7c61b83d.gif)
三、初遇signal
在实验三《Linux进程间通信》---“消息机制的示例程序”中有如下源码:
#include <sys/types.h> … … … void sigend(int); … … … int msgid; int main(void) { struct mymsg msgbuf; if((msgid=msgget(MY_KEY, IPC_CREAT|IPC_EXCL|0666)) < 0 ) { /* message queue exists, act as client */ … … … } else /* acts as server */ { signal(SIGINT, sigend); signal(SIGTERM, sigend); … … … } } } void sigend(int sig) { msgctl(msgid, IPC_RMID, 0); exit(0); }
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/7f536a30ffe280663d37a11cc094045d.gif)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/db22e94590544cc669933612be922231.gif)
四、Signal通信简介
1、基本知识
软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。第二种方法是忽略某个信号,对该信号不做任何处理,就象未发生过一样。第三种方法是对该信号的处理保留系统的默认值。这种缺省操作,对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。
表头文件: #include<signal.h>
功 能: 设置某一信号的对应动作
函数原型 : void (*signal(intsignum,void(* handler)(int)))(int);
或者:typedef void(*sig_t) ( int );
sig_t signal(int signum,sig_t handler);
参数说明:
第一个参数signum指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。
第二个参数handler描述了与信号关联的动作,它可以取以下三种值:
(1)一个无返回值的函数地址
此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为sig的信号时,就执行handler 所指定的函数。这个函数应有如下形式的定义:
void func(int sig);
sig是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。
(2)SIGIGN
这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号。
(3)SIGDFL
这个符号表示恢复系统对信号的默认处理。
函数说明 :
signal()会依参数signum指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行。当一个信号的信号处理函数执行时,
如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
返回值: 返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
附加说明 :在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,如果要改变此操作请改用sigaction()。
下面的情况可以产生Signal:
1. 按下CTRL+C产生SIGINT
2. 硬件中断,如除0,非法内存访问(SIGSEV)等等
3. Kill函数可以对进程发送Signal
4. Kill命令。实际上是对Kill函数的一个包装
2.Signals
各种信号的基本信息如下;Signal | Description |
SIGABRT | 由调用abort函数产生,进程非正常退出 |
SIGALRM | 用alarm函数设置的timer超时或setitimer函数设置的interval timer超时 |
SIGBUS | 某种特定的硬件异常,通常由内存访问引起 |
SIGCANCEL | 由Solaris Thread Library内部使用,通常不会使用 |
SIGCHLD | 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略 |
SIGCONT | 当被stop的进程恢复运行的时候,自动发送 |
SIGEMT | 和实现相关的硬件异常 |
SIGFPE | 数学相关的异常,如被0除,浮点溢出,等等 |
SIGFREEZE | Solaris专用,Hiberate或者Suspended时候发送 |
SIGHUP | 发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送 |
SIGILL | 非法指令异常 |
SIGINFO | BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程 |
SIGINT | 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 |
SIGIO | 异步IO事件 |
SIGIOT | 实现相关的硬件异常,一般对应SIGABRT |
SIGKILL | 无法处理和忽略。中止某个进程 |
SIGLWP | 由Solaris Thread Libray内部使用 |
SIGPIPE | 在reader中止之后写Pipe的时候发送 |
SIGPOLL | 当某个事件发送给Pollable Device的时候发送 |
SIGPROF | Setitimer指定的Profiling Interval Timer所产生 |
SIGPWR | 和系统相关。和UPS相关。 |
SIGQUIT | 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程 |
SIGSEGV | 非法内存访问 |
SIGSTKFLT | Linux专用,数学协处理器的栈异常 |
SIGSTOP | 中止进程。无法处理和忽略。 |
SIGSYS | 非法系统调用 |
SIGTERM | 请求中止进程,kill命令缺省发送 |
SIGTHAW | Solaris专用,从Suspend恢复时候发送 |
SIGTRAP | 实现相关的硬件异常。一般是调试异常 |
SIGTSTP | Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程 |
SIGTTIN | 当Background Group的进程尝试读取Terminal的时候发送 |
SIGTTOU | 当Background Group的进程尝试写Terminal的时候发送 |
SIGURG | 当out-of-band data接收的时候可能发送 |
SIGUSR1 | 用户自定义signal 1 |
SIGUSR2 | 用户自定义signal 2 |
SIGVTALRM | setitimer函数设置的Virtual Interval Timer超时的时候 |
SIGWAITING | Solaris Thread Library内部实现专用 |
SIGWINCH | 当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程 |
SIGXCPU | 当CPU时间限制超时的时候 |
SIGXFSZ | 进程超过文件大小限制 |
SIGXRES | Solaris专用,进程超过资源限制的时候发送 |
五、司机售票员问题
问题描述:创建driver进程代表司机,seller进程代表售票员。
售票员捕捉SIGINT(代表开车),发SIGUSR1给司机,司机打印("let's go")。
售票员捕捉SIGQUIT(代表停车),发SIGUSR2给司机,司机打印("stop the bus")
司机捕捉SIGTSTP(代表车到总站),发SIGUSR1给售票员,售票员打印("please get off thebus")
Driver.c源代码如下:
/* Driver.c: Act as driver *author : houjialin *To compile: gcc Driver.c –o driver */ #include<unistd.h> #include<signal.h> #include<stdlib.h> #include<error.h> #include<stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #define SHM_Key 3003 //共享存储区Key int shmid;//共享存储区ID int *shmptr; int Sellerpid; void CreatSHM()//创建共享存储区,将自己的进程ID放入其中 { if((shmid=shmget(SHM_Key, sizeof(int), IPC_CREAT|0666)) < 0) printf("shmget error"),exit(1); if((shmptr=(int *)shmat(shmid, 0, 0)) == (int *)-1) printf("shmat error"),exit(1); *shmptr=getpid(); } void driversigusr1(int signo) { printf("let's go\n"); } void driversigusr2(int signo) { printf("stop the bus\n"); } void driversigtstp(int signo) { kill(Sellerpid,SIGUSR1); } int main() /*act as Driver*/ { CreatSHM(); while(*shmptr==getpid());//等待Seller将自己pid放入SHM Sellerpid=*shmptr; signal(SIGUSR1,driversigusr1);//Driver对信号SIGUSR1响应函数driversigusr1 signal(SIGUSR2,driversigusr2);//Driver对信号SIGUSR2响应函数driversigusr2 signal(SIGTSTP,driversigtstp);//Driver对信号SIGSTSP(Ctrl + z)响应函数driversigtstp while(1); }
Seller.c源代码如下:
/* Seller.c: Act as Seller *author : houjialin *To compile: gcc Seller.c –o seller */ #include<unistd.h> #include<signal.h> #include<stdlib.h> #include<error.h> #include<stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #define SHM_Key 3003 //共享存储区Key int shmid; int *shmptr; int Driverpid;//司机进程ID void getID()//通过共享存储区获取Driverpid,并将自己的放入其中 { shmid=shmget(SHM_Key, sizeof(int), 0666); shmptr=(int *)shmat(shmid, 0, 0); Driverpid=*shmptr; *shmptr=getpid(); } void sellersigint(int signo) { kill(Driverpid,SIGUSR1); } void sellersigquit(int signo) { kill(Driverpid,SIGUSR2); } void sellersigusr1(int signo) { printf("\nplease get off the bus\n"); } int main()//act as Seller { getID(); signal(SIGINT, sellersigint);//Seller对信号SIGINT(Ctrl + c)响应函数sellersigint signal(SIGQUIT,sellersigquit);//Seller对信号SIGQUIT(Ctrl + \)响应函数sellersigquit signal(SIGUSR1,sellersigusr1); //Seller对信号SIGUSR1响应函数sellersigusr1 while(1); }
运行结果如下:
Driver.c | Selller.c |
houjialin@houjialin-ThinkPad-Edge:~/Documents$ ./driver let's go stop the bus ^Z | houjialin@houjialin-ThinkPad-Edge:~/Documents/期中$ ./seller ^C^\ please get off the bus |
当在seller进程中按下Ctrl+c(Ctrl+\,Ctrl+z同理)时,seller通过Signal捕获该信号,然后调用sellersigint函数处理该信号。Sellersigint函数通过系统调用kill发送SIGUSR1给driver进程(通过进程ID标识)。在driver进程中,当捕获到SIGUSR1后,掉用函数driversigusr1打印let’s go.
六、总结
到此,通过Signal删除消息队列的原理已经基本明白了。当按下Ctrl+C结束该进程时(Kill同理),当前进程通过Signal捕获该信号然后调用sigend(int) 处理。在sigend(int) 中,通过msgctl(msgid, IPC_RMID, 0)删除相应的消息队列。
以上只是对Signal通信的一些简单的介绍。在Linux操作系统中,许多系统进程通过Signal进行通信此处尚未涉及,有待今后研究。
附录一:
msgServe.c源代码:/* msgServe.c: Act as Serve *author : houjialin *To compile: gcc msgServe.c –o msgServe */ #include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #define Histype 4 #define Mytype 3 #define MY_KEY 20 struct mymessage { long mtype; char buffer[200]; } message; int msgid; void server() { msgid=msgget(MY_KEY, IPC_CREAT|IPC_EXCL|0666); if(msgid<0) { printf("消息队列已经存在!"); exit(0); } printf("server start:\n"); while(1) { msgrcv(msgid,&message,sizeof(struct mymessage),Histype,0); printf("Question is:\n%s", message.buffer); printf("Here is the answer :\n"); fgets(message.buffer,sizeof(struct mymessage)-sizeof(long)-1,stdin); message.mtype=Mytype; msgsnd(msgid, &message, sizeof(struct mymessage), 0); } } int main() { server(); }
msgClient源代码:
/* msgClient.c: Act as Client *author : houjialin *To compile: gcc msgClient.c –o msgClient */ #include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #define Mytype 4 #define Histype 3 #define MY_KEY 20 struct mymessage { long mtype; char buffer[200]; } message; int msgid; void client() { msgid=msgget(MY_KEY, 0666); if(msgid>=0) printf("welcome to numeber %d queue!Input your questions\n",msgid); else { exit(0); } fgets(message.buffer, sizeof(struct mymessage)-sizeof(long)-1, stdin); while(1) { message.mtype=Mytype; msgsnd(msgid, &message, sizeof(struct mymessage), 0); msgrcv(msgid,&message,sizeof(struct mymessage),Histype,0); printf("The answer is: %sInput your question:\n",message.buffer); fgets(message.buffer,sizeof(struct mymessage)-sizeof(long)-1,stdin); } } int main() { client(); }
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/07/ec9ddadee5f14dd9559ba30bc7a80944.gif)
相关文章推荐
- Linux下signal通信研究(操作系统期中论文之自选题目研究)
- Linux进程间通信(五)---信号通信之signal()、信号集函数组及其基础实验
- VM 操作系统实例化(基于 KVM 的虚拟化研究及应用--崔泽永(2011))的论文笔记
- 【科研论文】基于嵌入式Linux的以太网视频高速传输研究
- 在 Linux“.NET研究” 操作系统中运行 ASP.NET 4 (下)
- linux操作系统常用面试题目
- linux通信机制signal()函数详解
- Linux操作系统下的TCP/IP网络通信
- 读书笔记之: 操作系统概念(第6版)-第七部分 案例研究-Linux
- Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知
- SSH实现Linux操作系统远程无密登录,通信传输
- 操作系统和linux编程常考题目
- Linux下生产者消费者问题详细分析(操作系统期中考试论文---并发程序的同步和互斥)
- Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知
- 操作系统和linux编程常考题目
- Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知
- Linux进程间通信(五)---信号通信之signal()、信号集函数组及其基础实验
- 操作系统和linux编程常考题目
- Linux操作系统下的串口通信
- Linux下的C语言编程——进程间通过signal函数通信简单操作