免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3228 | 回复: 3
打印 上一主题 下一主题

有时候会产生僵尸进程, 帮忙分析一下 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-10-03 15:30 |只看该作者 |倒序浏览
本帖最后由 KevinLee39 于 2010-10-03 17:07 编辑

我写的一个调度程序, 测试时有时候会产生僵尸进程(大概1/5的概率吧),  而且碰到这种情况, 主进程也停住不动了, 不知道停在哪里, 实在找不出原因了.

测试运行情况:
perl diaodu.pl cs 4
开始时间: 2010-10-03 15:19:11 pid: 7324 Version: 1.2.r33 2010-09-26
child 00 branch: 650100 pid: 7325 2010-10-03 15:19:11
child 01 branch: 650200 pid: 7326 2010-10-03 15:19:11
child 02 branch: 652100 pid: 7327 2010-10-03 15:19:11

另一个窗口里看进程的情况:
  xjv8js  7327  7324  1 15:19:11 pts/ts    0:00 <defunct>
  xjv8js  7325  7324  1 15:19:11 pts/ts    0:00 <defunct>
  xjv8js  7527 11176  0 15:24:15 pts/tk    0:00 grep 7324
  xjv8js  7328  7324  1 15:19:11 pts/ts    0:00 <defunct>
  xjv8js  7324  8015  0 15:19:11 pts/ts    0:00 perl diaodu.pl cs 4
  xjv8js  7326  7324  1 15:19:11 pts/ts    0:00 <defunct>

源码:

  1. #! /usr/bin/perl
  2. #

  3. my @branch = qw(
  4.         650100 650200 652100 652200 652300 652700 652800 652900
  5.         653000 653100 653200 654000 654100 654200 654300 659000
  6. );

  7. my $startdate = '20100101'; # 采集开始日期
  8. my $enddate   = '20100930'; # 采集结束日期

  9. (our $REV = '$LastChangedRevision:: 33 ) =~ s/\D+(\d+)\D+/$1/g;
  10. (our $REVDATE='$LastChangedDate:: 2010-09-26#)=~s/.+(\d{4}-\d\d-\d\d).+/$1/g;
  11. (our $VERSION = '1.2.r'.$REV);
  12. use warnings;
  13. #use strict;
  14. use Cwd;
  15. use FindBin qw($Bin);
  16. use POSIX;
  17. use POSIX ":sys_wait_h";

  18. sub usage {
  19.         print "
  20. Usage: $0 cj|sj|xz 并行进程个数
  21.        cj 采集
  22.        sj 审计
  23.        xz 下载
  24.    Ex: $0 cj 4

  25. Version: $VERSION $REVDATE

  26. ";
  27. }

  28. # 测试
  29. my $cs =q#"date; sleep " . int(rand(40))#;
  30. # 采集
  31. my $cj =q#"sh collectdata.sh 1 $branch \\\\\# \\\\\# $startdate $enddate C O"#;
  32. # 审计
  33. my $sj =q#"cbps_4003_bat_AuditDataConsistency 1 $branch "#;
  34. # 下载
  35. my $xz =q#"cbps_4004_bat_DataDownLoad 1 $branch "#;

  36. #
  37. # main
  38. #
  39. if (@ARGV != 2 or ($ARGV[0] ne 'cs' and $ARGV[0] ne 'cj'
  40.         and $ARGV[0] ne 'sj' and $ARGV[0] ne 'xz')) {
  41.         &usage();
  42.         exit(-1);
  43. }

  44. $|++;
  45. my $mode     = $ARGV[0];        # 运行模式: 采集,下载等
  46. my $binxindu = $ARGV[1];        # 希望的并行进程个数
  47. my $child = 0;                        # 当前并行进程个数(正在跑的有几个)
  48. my $position  = -1;                # 正在/已经采集的个数(采集到了哪个机构)
  49. my $done_branch = 0;                # 已经采集完毕的个数
  50. my $child_pid;
  51. my %pid_branch;

  52. print "开始时间: ".&get_time()." pid: $ Version: $VERSION $REVDATE\n";

  53. my $sigset=POSIX::SigSet->new(&POSIX::SIGCHLD,&POSIX::SIGUSR1,&POSIX::SIGUSR2);
  54. my $action = POSIX::SigAction->new('reaper',
  55.                                    $sigset,
  56.                                    0);
  57. POSIX::sigaction(&POSIX::SIGCHLD, $action);
  58. $action = POSIX::SigAction->new('add_binxindu',
  59.                                 $sigset,        
  60.                                 0);
  61. POSIX::sigaction(&POSIX::SIGUSR1, $action);
  62. $action = POSIX::SigAction->new('minus_binxindu',
  63.                                 $sigset,        
  64.                                 0);
  65. POSIX::sigaction(&POSIX::SIGUSR2, $action);

  66. # 启动
  67. while(1) {
  68.         &run();
  69.         if ($done_branch == @branch) {
  70.                 print "全部机构采集完毕\n";
  71.                 print "结束时间: ".&get_time()."\n";
  72.                 exit(0);
  73.         }
  74.         if ($binxindu == 0 && $child == 0) {
  75.                 print "当前并行度为0, 完成的数量: $done_branch\n";
  76.                 print "退出时间: ".&get_time()."\n";
  77.                 exit(0);
  78.         }
  79.         pause();
  80. }
  81. # end main

  82. #
  83. # 按照当前并行度设定启动适当数量的子进程
  84. #
  85. sub run {
  86.         while($child < $binxindu && $position+1 < @branch) {
  87.                 &add_child();
  88.         }
  89. }

  90. #
  91. # 处理子进程终止
  92. #
  93. sub reaper {
  94.         while (($child_pid = waitpid(-1,WNOHANG)) > 0) {
  95.                 print "child $pid_branch{$child_pid} branch: "
  96.                             ."$branch[$pid_branch{$child_pid}] pid: $child_pid "
  97.                      .&get_time()." done\n";
  98.                 $child--;
  99.                 $done_branch++;
  100.         }
  101. }

  102. #
  103. # 增加一个并行度
  104. #
  105. sub add_binxindu {
  106.         $binxindu++;
  107.         print "add process to $binxindu\n";
  108.         &run();
  109.         print "child:           $child\n";
  110.         print "done_branch:     $done_branch\n";
  111. }

  112. #
  113. # 减少一个并行度
  114. #
  115. sub minus_binxindu {
  116.         if ($binxindu > 0) {
  117.                 $binxindu--;
  118.         }
  119.         print "minus binxindu to $binxindu\n";
  120.         print "child:           $child\n";
  121.         print "done_branch:     $done_branch\n";

  122. }

  123. #
  124. # 增加一个并行进程
  125. #
  126. sub add_child {
  127.         my $pid = fork;
  128.         if (!defined($pid)) {
  129.                 print "child branch: $branch[$position+1] fork failed!\n";
  130.         } elsif ($pid > 0) {
  131.                 # father process
  132.                 $position++;
  133.                 $pid_branch{"$pid"} = sprintf("%02d", $position);
  134.                 print "child $pid_branch{$pid} branch: $branch[$position] "
  135.                       ."pid: $pid ".&get_time()."\n";
  136.                 $child++;
  137.         } else {
  138.                 # child process
  139.                 open STDOUT, ">>$mode$branch[$position].log";
  140.                 open STDERR, ">>&STDOUT";
  141.                 my $commander = eval qq(eval "\$mode"); # mode前面是连续2个$符号, 帖子里发表不出来.
  142.                 print "$commander\n"; exit(0);
  143.                 #exec $commander;
  144.         }
  145. }

  146. #
  147. # 获取当前时间
  148. #
  149. sub get_time {
  150.         my $time_str = strftime("%Y-%m-%d %H:%M:%S", localtime);
  151.         return $time_str;
  152. }

复制代码

论坛徽章:
0
2 [报告]
发表于 2012-05-31 11:05 |只看该作者
信号不排队的,错过了就没了。
应该是你在while的时候又信号进来,但是你错过了,所以产生了僵尸进程

论坛徽章:
0
3 [报告]
发表于 2012-05-31 15:46 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
4 [报告]
发表于 2012-05-31 17:53 |只看该作者
楼主应该多看看大骆驼里面进程和信号2章
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP