首页 > 代码库 > Linux进程间的通信

Linux进程间的通信

一.进程与线程

  1. 进程是程序在某个数据集合上的一次运行活动,线程是进程中一个执行路径。进程有自己独立的地址空间,而线程没有,线程必须依赖进程而存在。
  2. 进程是系统资源分配的单位,线程是系统调度的单位
  3. 操作系统以进程为单位分配资源,进程中的每个线程共享进程的资源,每个线程有自己的程序计数器、栈。

二.进程启动的三种方式

  1. system("ps -ef"),使用shell启动一个新的进程
  2. exec族函数会用新进程代替原有的进程,系统会从新的进程运行,新的进程的PID值会与原来的进程的PID值相同。
  3. fork函数复制进程映像,创建一个新的进程,新进程的许多属性与当前进程是相同的,执行代码也完全相同,但新进程有自己的数据空间、环境、文件描述符。

三.孤儿进程和僵死进程

  在linux中,子进程总是由父进程产生的,子进程和父进程是同时运行着的,父进程无法预知子进程什么时候结束,当一个进程完成它的工作后,父进程需要调用waitpid系统调用获取子进程的终止状态。孤儿进程指的是父进程已经运行结束了,而它的子进程还在运行,那么那些子进程将称为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。僵尸进程指的是一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程,进程处于僵死状态很明显,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。有两种方法可以避免僵死进程,一种是子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号,在信号处理函数中调用wait进行处理僵尸进程;另外一种是创建进程的时候fork两次,原理是将子进程成为孤儿进程,从而其父进程变为init进程,通过init进程可以处理僵死进程。具体可以参考《孤儿进程和僵死进程总结

四.进程与信号

  信号提供了一种处理异步事件的方法。每个信号都有一个名字。这些名字都以三个字符SIG开头。在头文件<signal.h>中,这些信号都被定义为正整数(信号编号)。不存在编号为0的信号。(kill函数对信号编号0有特殊的应用)。信号是异步事件的经典实例。产生信号的事件对进程而言是随机出现的。进程不能简单地测试一个变量(例如errno)来判别是否出现了一个信号,而是必须告诉内核“在此信号出现时,请执行下列操作”。下面的实例是通过信号机制处理僵死进程,子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。

产生信号的方式:

  • 当用户按某些终端键时,引发终端产生的信号。
  • 硬件异常产生信号。
  • 进程调用kill(2)函数可将信号发送给另一个进程或进程组。(接收信号进程和发送信号进程的所有者必须相同,或者发送信号进程的所有者必须是超级用户。)
  • 用户可用kill(1)命令将信号发送给其他进程。

可以要求内核在某个信号出现时按照下列三种方式之一进行处理,我们称之为信号的处理或者与信号相关的动作。

  • 忽略此信号。大多数信号都可使用这种方法进行处理,但是有两种信号决不能被忽略:SIGKILL和SIGSTOP。这两种信号不能被忽略的原因是:它们向超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(例如除以0),则进程的运行行为是未定义的。
  • 捕捉信号。为了做到这一点,要通知内核在某种信号发生时调用一个用户函数。在用户函数中,可执行用户希望对这种事件进行的处理。注意,不能捕捉SIGKILL和SIGSTOP信号。
  • 执行系统默认动作。注意,针对大多数信号的系统默认动作是终止

 

技术分享
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <errno.h>
 4 #include <stdlib.h>
 5 #include <signal.h>
 6 
 7 static void sig_child(int signo);
 8 
 9 int main()
10 {
11     pid_t pid;
12     //创建捕捉子进程退出信号
13     signal(SIGCHLD,sig_child);
14     pid = fork();
15     if (pid < 0)
16     {
17         perror("fork error:");
18         exit(1);
19     }
20     else if (pid == 0)
21     {
22         printf("I am child process,pid id %d.I am exiting.\n",getpid());
23         exit(0);
24     }
25     printf("I am father process.I will sleep two seconds\n");
26     //等待子进程先退出
27     sleep(2);
28     //输出进程信息
29     system("ps -o pid,ppid,state,tty,command");
30     printf("father process is exiting.\n");
31     return 0;
32 }
33 
34 static void sig_child(int signo)
35 {
36      pid_t        pid;
37      int        stat;
38      //处理僵尸进程
39      while ((pid = waitpid(-1, &stat, WNOHANG)) >0)
40             printf("child %d terminated.\n", pid);
41 }
View Code

 

五.进程与管道

 

 

 

 

参考:

  • 孤儿进程与僵尸进程[总结]

  • 进程与信号

 

Linux进程间的通信