来自 金沙澳门官网网址 2019-10-04 22:34 的文章
当前位置: 金沙澳门官网网址 > 金沙澳门官网网址 > 正文

一声令下解释,进程间通讯

1、编写一段程序,使用系统调用fork( )创建两个子进程,再用系统调用signal( )让父进  程捕捉键盘上来的中断信号(即按ctrl+c键),当捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后,分别输出下列信息后终止:  

ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 3532 0.0 0.2 2428 452 ? Ss 20:40 0:00 gpm -m /dev/input/mice -t imps2
htt 3564 0.0 1.7 29460 3704 ? Sl 20:41 0:00 htt_server -nodaemon
root 3574 0.0 0.4 5236 992 ? Ss 20:41 0:00 crond
root 3627 0.0 0.2 3448 552 ? SNs 20:41 0:00 anacron -s
root 3636 0.0 0.1 2304 420 ? Ss 20:41 0:00 /usr/sbin/atd
ubuntu2 3655 0.0 0.5 13840 1084 ? Ssl 20:41 0:00 dbus-daemon-1 --system

parent process is killed!

注:信号代码可以省略;我们常用的信号代码是 -9 ,表示强制终止;

 

int main(int argc, char* argv[])
{
while(1)
{
pid_t chi = fork();
if(chi == 0)
{
execl("/bin/bash","bash","-c","ls",NULL);
}
sleep(2);
}
}
会不停地产生僵死进程ls;

 

用法:killall 正在运行的程序名

Child process 1 is killed by parent!

D 不可中断 uninterruptible sleep (usually IO)
R 运行 runnable (on run queue)
S 中断 sleeping
T 停止 traced or stopped
Z 僵死 a defunct (”zombie”) process

关掉后一个wait

[[email protected] beinan]# pgrep -l gaim
2979 gaim
[[email protected] beinan]# killall gaim

^C

2 killall

 

kill [信号代码] 进程ID

parent process is killed!

在Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的“僵尸”进程。“僵尸”进程是一个早 已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。由于进程表的容量是有限的,所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数 目太多,还会导致系统瘫痪。 但是当 父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。

⑶该程序段前面部分用了两个wait(0),为什么?

[[email protected] beinan]# pgrep -l gaim
2979 gaim
[[email protected] beinan]# pkill gaim

Child process 2 is killed by parent!

子进程将成为孤儿进程

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

main()
{
pid_t pid;
pid = fork();
if(pid < 0)
printf("error occurred!n");
else if(pid == 0) {
sleep(6);
printf("I'm a orphann");
exit(0);
}
else {
sleep(1);
printf("Children Bye!n");
}
}

# ./a.out
Children Bye!
# I'm a orphan
(回车后将会进入#)
#
二、有什么害处:
僵尸进程会占用系统资源,如果很多,则会严重影响服务器的性能
孤儿进程不会占用系统资源
处理流程:
只要老爹不等wait(sys/wait.h)儿子,儿子都将成为孤魂野鬼zombie(zombie),unix中默认老爹总是想看儿子死后的状态(以便报仇)
if 老爹比儿子先再见
儿子将被init(id = 1)收养,最后的结果是zombie儿子彻底再见,系统资源释放
else
{
儿子的zombie将一直存在,系统资源占用...
if 老爹dead
儿子将被init(id = 1)收养,最后的结果是zombie儿子彻底再见,系统资源释放

else 类似的儿子zombie越来越多,系统就等死了!!!
}
三、如何防止僵尸进程
首先明白如何产生僵尸进程:
1、子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它
2、父进程没有调用wait()或waitpid()函数来等待子进程的结束
第一种方法: 捕捉SIGCHLD信号,并在信号处理函数里面调用wait函数
转贴Richard Steven的Unix Network Programming代码

int
main(int argc, char **argv)
{
...
Signal(SIGCHLD, sig_chld);
for(;
}
...
}

void
sig_chld(int signo)
{
pid_t pid;
int stat;

while ( (pid = waitpid(-1, &stat, WNOHANG)) >; 0)
printf("child %d terminatedn", pid);
return;
}
第二种方法:两次fork():转载
在《Unix 环境高级编程》里关于这个在8.6节有非常清楚的说明。

实例
回忆一下8 . 5节中有关僵死进程的讨论。如果一个进程要f o r k一个子进程,但不要求它等待
子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍是调用f o r k
两次。程序8 - 5实现了这一点。
在第二个子进程中调用s l e e p以保证在打印父进程I D时第一个子进程已终止。在f o r k之后,
父、子进程都可继续执行——我们无法预知哪一个会先执行。如果不使第二个子进程睡眠,则
在f o r k之后,它可能比其父进程先执行,于是它打印的父进程I D将是创建它的父进程,而不是
i n i t进程(进程ID 1)。

#include <sys/types.h>
#include <sys/wait.h>
#include "ourhdr.h"

int
main(void)
{
pid_t pid;

if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) { /* first child */
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid > 0)
exit(0); /* parent from second fork == first child */

/* We're the second child; our parent becomes init as soon
as our real parent calls exit() in the statement above.
Here's where we'd continue executing, knowing that when
we're done, init will reap our status. */

sleep(2);
printf("second child, parent pid = %dn", getppid());
exit(0);
}

if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
err_sys("waitpid error");

/* We're the parent (the original process); we continue executing,
knowing that we're not the parent of the second child. */

exit(0);
}
//avoid zombie process by forking twice
-----------------------------orphan.c#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{
pid_t pid;
pid = fork();
if(!pid){
while(1){
printf("A background process,PID:%dn,ParentID:%dn" ,getpid(),getppid());
sleep(3);
}
}
else if(pid > 0){
printf("I am parent process,my pid is %dn",getpid() );
exit(0);
}
else {
printf("Process creation failed!n");
}
return 0;
}
程序运行结果
I am parent process,my pid is 2026
A background process,PID:2027
,ParentID:2026
[email protected]:~/work/process_thread/fork2$ A background process,PID:2027
,ParentID:1
A background process,PID:2027
,ParentID:1
A background process,PID:2027
,ParentID:1
A background process,PID:2027
,ParentID:1
A background process,PID:2027
,ParentID:1
A background process,PID:2027
,ParentID:1
---------------------------------------------------------Zombie.c#include
  #include
  main()
  {
   pid_t pid;
  
   pid=fork();
  
   if(pid<0) /* 如果出错 */
   printf("error occurred!n");
   else if(pid==0) /* 如果是子进程 */
   exit(0);
   else /* 如果是父进程 */
   sleep(60); /* 休眠60秒,这段时间里,父进程什么也干不了 */
   wait(NULL); /* 收集僵尸进程 */

parent process is killed!root@kali:~/wyq/S4#

PS:运行例子,先gcc zombie1.c -o zombie编译,然后运行zombie;
然后可以可用ps -ef来查看是否产生了僵尸进程。
其他知识:
execl:進程進入了shell環境執行 執行完進程結束
system=fork+exec+waitpid:執行完進程仍然存在,只是用它的子進程執行了操作。

child process 1 is killed by parent!^C

3.僵尸进程的查看:
用top命令,可以看到
Tasks: 123 total, 1 running, 122 sleeping, 0 stopped, 0 zombie
zombie前面的数量就是僵尸进程到数量;
ps -ef
出现:
root 13028 12956 0 10:51 pts/2 00:00:00 [ls] <defunct>
最后有defunct的标记,就表明是僵尸进程。

 1 #include<stdio.h>
 2 #include<signal.h>
 3 #include<unistd.h>
 4 #include<sys/types.h>
 5 #include<sys/wait.h>
 6 int wait_mark;
 7 void waiting(),stop();
 8 void main()
 9 {int  p1, p2;
10 signal(SIGINT,stop);
11 while((p1=fork())==-1);
12 if(p1>0)                            /*在父进程中*/
13 {①
14 while((p2=fork())==-1);
15            If(p2>0)                    /*在父进程中*/
16             { ②
17                   wait_mark=1;
18                  waiting(0);
19                 kill(p1,10);
20                 kill(p2,12);
21                 wait( );
22                wait( );
23                printf("parent process is killed!n");
24                exit(0);
25             }
26            else                        /*在子进程2中*/
27            {
28 wait_mark=1;
29 signal(12,stop);
30 waiting();
31 lockf(1,1,0);
32 printf("child process 2 is killed by parent!n");
33 lockf(1,0,0);
34 exit(0);
35 }
36 } 
37 else                        /*在子进程1中*/
38 {
39       wait_mark=1;
40       signal(10,stop);
41       waiting();
42       lockf(1,1,0);
43       printf("child process 1 is killed by parent!n");
44       lockf(1,0,0);
45       exit(0);
46 }
47 }
48 void waiting()
49 {
50    while(wait_mark!=0);
51 }
52 void stop()
53 {
54    wait_mark=0;
55 }

举例:

child process 2 is killed by parent!

main()
{
if(!fork())
{
printf("child pid=%dn", getpid());
exit(0);
}
/*wait();*/
/*waitpid(-1,NULL,0);*/
sleep(60);
printf("parent pid=%d n", getpid());
exit(0);
}
60s内会不断产生僵尸进程,直到父进程exit(0);
如果在调用wait/waitpid来为子进程收尸,就不会产生僵尸进程了。

 

[[email protected] ~]# kill 4840 注:杀掉4840这个进程;
[[email protected] ~]# ps -auxf |grep httpd 注:查看一下会有什么结果?是不是httpd服务器仍在运行?
[[email protected] ~]# kill 4830 注:杀掉httpd的父进程;
[[email protected] ~]# ps -aux |grep httpd 注:查看httpd的其它子进程是否存在,httpd服务器是否仍在运行?

parent process is killed!root@kali:~/wyq/S4#

kill 的用法:

parent process is killed!

/*-----zombie2.c-----*/
#include <stdio.h>
#include<sys/types.h>

child process 1 is killed by parent!

#pkill 正在运行的程序名

 

[[email protected] ~]# ps auxf |grep httpd
root 4939 0.0 0.0 5160 708 pts/3 S+ 13:10 0:00 _ grep httpd
root 4830 0.1 1.3 24232 10272 ? Ss 13:02 0:00 /usr/sbin/httpd
apache 4833 0.0 0.6 24364 4932 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4834 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4835 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4836 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4837 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4838 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4839 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd
apache 4840 0.0 0.6 24364 4928 ? S 13:02 0:00 _ /usr/sbin/httpd

Parent process is killed!

  • 位于后台的进程组;
    l 多线程,克隆线程 multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
    WCHAN 正在等待的进程资源;

1-

ps以前就大约了解一点僵尸进程的概念,今天再好好地通过网上资源并实际写C程序实验了,现在对僵尸进程总结一下。
1.僵尸进程概念:
僵尸进程(ZombieProcess):就是已经结束了的进程,但是没有从进程表中删除。太多了会导致进程表里面条目满了,进而导致系统崩溃,倒是不占用其他系统资源。
在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。

^C

killall 也和ps或pgrep 结合使用,比较方便;通过ps或pgrep 来查看哪些程序在运行;

^C

4.僵尸进程解决办法:
4.1 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行 waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
4.2 把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。
kill -9 `ps -ef | grep "Process Name" | awk '{ print $3 }'`
其中,“Process Name”为处于zombie状态的进程名。
4.3 杀父进程不行的话,就尝试用skill -t TTY关闭相应终端,TTY是进程相应的tty号(终端号)。但是,ps可能会查不到特定进程的tty号,这时就需要自己判断了。
4.4 实在不行,重启系统吧,这也是最常用到方法之一。

⑴运行程序并分析结果。

终止一个进程或终止一个正在运行的程序,一般是通过 kill 、killall、pkill、xkill 等进行。比如一个程序已经死掉,但又不能退出,这时就应该考虑应用这些工具。

child process 1 is killed by parent!

用法:

^C

killall 通过程序的名字,直接杀死所有进程,咱们简单说一下就行了。

⑵如果把signal(SIGINT,stop)放在①号和②号位置,结果会怎样并分析原因。

pgrep 是通过程序的名字来查询进程的工具,一般是用来判断程序是否正在运行。在服务器的配置和管理中,这个工具常被应用,简单明了;

2-

子进程持续10秒钟的僵尸状态(EXIT_ZOMBIE)

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

main()
{
pid_t pid;
pid = fork();
if(pid < 0)
printf("error occurred!n");
else if(pid == 0) {
printf("Hi father! I'm a ZOMBIEn");
exit(0); //(1)
}
else {
sleep(10);
wait(NULL); //(2)
}
}

(1) 向父进程发送SIGCHILD信号
(2) 父进程处理SIGCHILD信号

执行exit()时根据其父进程的状态决定自己的状态:
如果父进程已经退出(没有wait),则该子进程将会成为孤儿进程过继给init进程
如果其父进程还没有退出,也没有wait(),那么该进程将向父进程发送SIGCHILD信号,进入僵尸状态等待父进程为其收尸。如果父进程一直没有执行wait(),那么该子进程将会持续处于僵尸状态。

child process 2 is killed by parent!

au(x) 输出格式 :

child process 2 is killed by parent!gcc -o S4_1-3.out S4_1-3.c

另外应用的场合就是在服务器管理中,在不涉及数据库服务器程序的父进程的停止运行,也可以用这些工具来终止。为什么数据库服务器的父进程不能用这些工具杀死呢?原因很简单,这些工具在强行终止数据库服务器时,会让数据库产生更多的文件碎片,当碎片达到一定程度的时候,数据库就有崩溃的危险。比如mysql服务器最好是按其正常的程序关闭,而不是用pkill mysqld 或killall mysqld 这样危险的动作;当然对于占用资源过多的数据库子进程,我们应该用kill 来杀掉。

child process 2 is killed by parent!

  }

本文由金沙澳门官网网址发布于金沙澳门官网网址,转载请注明出处:一声令下解释,进程间通讯

关键词: