免费注册 查看新帖 |

Chinaunix

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

!!并发守护进程的问题(急)附源码,大家帮我看看!! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-08-25 16:57 |只看该作者 |倒序浏览
#include <sys/wait.h>
#include <signal.h>
#include <sys/resource.h>
#include <fcntl.h>
#include "nsi_srv.h"

#define PROCNAME "nsi_srv_batch"
#define printusage() \
                printf("   Usage:%s [-d num|-k] [-h]\n",PROCNAME);    \
                printf("         -d num以守护方式启动服务,num最大进程数,最小和缺省为4,最大不能超过99\n");    \
                printf("         -k 停止服务\n");    \
                printf("         -h 显示帮助\n");    \
                printf("         -d与-k不能同时出现\n");    \
                printf("   EXAMP:1. %s -d\n", PROCNAME);    \
                printf("         2. %s -k\n", PROCNAME);    \
                printf("         3. %s -h\n", PROCNAME);

#define errexit(aerrtxt) \
                elog(6,"%s", aerrtxt);    \
                dbrollback();    \
                dbclose();    \
                exit(EXIT_FAIL);

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;
    typedef struct{
        char jyr[8+1];                    /*服务交易日*/
        char stepid[6+1];            /*步骤号*/
        char srvid[18+1];                /*服务编号*/
    } Stru_StepDef;
EXEC SQL END DECLARE SECTION;

pid_t mpid;
int imaxp=4;
int iwaitfechs=600;  /*数据库取数据等待秒数*/
int iwaitforks=60;     /*fork错误等待秒数*/
int imaxforkerrs=10; /*最大fork尝试次数*/

void vfun(int i)
{
         pid_t subpid;
         
         subpid=getpid();
     elog(6,"[NB98]subpid=[%s]第[%d]个虚拟子进程产生成功!!cmd=[%s]",subpid,i);
     sleep(100);
}

void subp(const char *jyr, const char *stepid)
{               
                char cmd[256];
                pid_t subpid;
                int iret=0;
               
                subpid=getpid();
                memset((char *)cmd, 0x00, sizeof(cmd));
                    
                sprintf(cmd,"echo %d > %s/log/errlog/%d.pid", subpid,(char *)getenv("HOME"),subpid);
          iret=system(cmd);
          sleep(5);
          if (iret!=0)
          {
                  elog(6,"[NB99]subpid=[%s]运行子作业失败!!cmd=[%s]",subpid,cmd);
          }
          else
          {
                  elog(6,"[NB99]subpid=[%s]运行子作业成功!!cmd=[%s]",subpid,cmd);
          }
        //exit(0);


}


int daemon_init(void)
{
      pid_t pid;
      struct sigaction sa;
      struct rlimit r1;
      int i;
      
      elog(6,"sigaction begin!!");
      if ((pid = fork()) < 0)
              return -1;
      else if (pid != 0)
              exit(0);
      if (setsid() < 0)
              exit(1);
            elog(6,"sigaction 1!!");
      sa.sa_handler = SIG_IGN;
      sigemptyset(&sa.sa_mask);
      sa.sa_flags = 0;
      if (sigaction(SIGHUP, &sa, NULL) < 0)
      {
              //printf("sigaction error\n");


              elog(6,"sigaction error");
              exit(1);
      }
      elog(6,"sigaction 2!!");
      if ((pid = fork()) < 0)
              return -1;
      else if (pid != 0)
              exit(0);

      if (chdir("/") < 0)
              return -1;
      elog(6,"sigaction 3!!");
      
      umask(0);
      if (getrlimit(RLIMIT_NOFILE, &r1) < 0)
      {
               //printf("get file limit error\n");


               elog(6,"get file limit error");
               exit(1);
      }
      elog(6,"sigaction 4!!");
      if (r1.rlim_max == RLIM_INFINITY)
               r1.rlim_max = 1024;
      for(i = 0; i < r1.rlim_max; i++)
               close(i);
      elog(6,"sigaction 5!!");
      elog(6,"pid=[%d]!!",getpid()); ---这里可以取到进程号!!!!
      return 0;
}

论坛徽章:
0
2 [报告]
发表于 2007-08-25 16:59 |只看该作者
接上面......

int mainp()
{
    EXEC SQL BEGIN DECLARE SECTION;
          Stru_StepDef str_step;
    EXEC SQL END DECLARE SECTION;
   
    pid_t pid,ipid1;
  int i=5,iforkerrs=0;
  int n;
  long j = 0;
  
    /*启动守护进程*/
    n = daemon_init();
    elog(6,"daemon_init[%d]!!",n); ---这个有返回!!!!
  if (n != 0)
  {
      elog(6,"[NB03]后台服务守护进程启动..失败!!rtn=%d",n);
      exit(1);
  }
  
  /*取得父进程的pid号*/
  ipid1=getpid(); ----取不出来!!!!
  mpid=ipid1;
  
  elog(6,"mpid=[%s]!!",mpid);
  elog(6,"[NB03]mpid=[%s]后台服务守护进程启动...成功!!",mpid);

    //imaxp=5;


    i=imaxp;
  while (i--)
  {
          iforkerrs=0;
         
          if ((pid = fork()) < 0)
      {
          iforkerrs++;
        elog(6,"[NB04]mpid=[%s]子进程产生失败,进行第[%d]次尝试!!",mpid,iforkerrs);
                exit(1);
      }
      if (pid == 0)
      {
              vfun(imaxp-i-1); /*虚拟子进程,初始化为5个*/
              exit(0);
      }
    }
   
  elog(6,"%s!!", "初始化5个成功!!");
  
  if (0!=dbconnect())
  {
    elog(6,"[NB01]连接数据库...失败!!sqlcode=%d",SQLCODE);
    exit(EXIT_FAIL);
  }
  
  elog(6,"[NB01]连接数据库...成功!!");
  
    EXEC SQL DECLARE cur_step CURSOR FOR
                     SELECT jyr, stepid, srvid
                     FROM nsi_srv_parall
                     WHERE isdone='0' AND isvalid='0' ORDER BY jyr,stepid;
   
    EXEC SQL OPEN cur_step;
    if( SQLCODE !=0 )
  {
      elog(6,"[NB02]服务类型作业配置表游标打开...失败!!sqlcode=%d",SQLCODE);
      //Batch_Err(sprocname, scurjyr, s_errtxt);


      EXEC SQL CLOSE cur_step;
      dbdisconnect();
            exit(EXIT_FAIL);
  }
   
    elog(6,"[NB02]服务类型作业配置表游标打开...成功!!");
  
  j = 0;
  while (wait(NULL) > 0)
  {
          /*从作业表中取作业,如果没有作业则等待*/
          while (1)
          {
                  memset((Stru_StepDef *)&str_step, 0x00, sizeof(Stru_StepDef));
                    EXEC SQL FETCH cur_step into :str_step;
                    if (NODATA) /*没有数据则循环等待10分钟*/
                    {
                            elog(6,"[NB05]mpid=[%s]没有作业需要运行,等待[%d]秒!!",mpid,iwaitfechs);
                            sleep(600);
                            continue;
                    }
                    if(SQLCODE!=0 && SQLCODE!=1405 && SQLCODE!=1403)
                    {
                        elog(6,"[NP05]mpid=[%s]从服务类型作业表中取数据...失败,退出!!sqlcode=%d",mpid,SQLCODE);
                        //Batch_Err(sprocname, scurjyr, s_errtxt);


                            sleep(600);
                            continue;
                            //errexit(s_errtxt);


                    }
                    break;
            }
            elog(6,"[NB05]mpid=[%s]从服务作业表中取数据...成功!!jry=[%s],stepid=[%s],srvid=[%s]", \
                                                mpid,str_step.jyr,str_step.stepid,str_step.srvid);
         
          /*产生子进程*/
          iforkerrs=0;
          //while(1)


          //{


                if ((pid = fork()) < 0)
                {
                  iforkerrs++;
                  elog(6,"[NB06]mpid=[%s]子进程产生失败,进行第[%d]次尝试!!",mpid,iforkerrs);
                  //if (iforkerrs>imaxforkerrs);


                  //{


                  // sprintf(s_errtxt,"[NB06]mpid=[%s]产生子进程失败,尝试超过[%s]次...退出!!",mpid,imaxforkerrs);


                              //Batch_Err(sprocname, scurjyr, s_errtxt);


                                 EXEC SQL CLOSE cur_step;
                                 dbdisconnect();
                                    exit(1);
                 // }


                  /*等待再尝试*/
                  //sleep(iwaitforks);


                  //continue;


                }
                //break;


         // }


        
        if (pid == 0) /*子进程*/
        {
                  j++;
                  elog(6,"[NB06]mpid=[%s]产生总第[%ld]个子进程进行作业处理!!",mpid,j);
          subp((char *)str_step.jyr,(char *)str_step.stepid);
          exit(0);
        }
  }
  EXEC SQL CLOSE cur_step;
  dbdisconnect();
  return 0;
}

程序运行产生的log如下:
16:30:56->sigaction
16:30:56->sigaction
16:30:56->sigaction
16:30:56->sigaction
16:30:56->sigaction
16:30:56->sigaction
16:30:56->pid=[5906]!!
16:30:56->daemon_init[0]!!

目前程序执行到daemon_init();
处并没有产生后台进程,随后的getpid()无法取得父进程号,后面的子进程也都没产生。

我加pro*c部分前是可以的,请各位大侠帮助看看,顺便帮我看看我的代码,还有那些问题。。

论坛徽章:
0
3 [报告]
发表于 2007-08-25 17:00 |只看该作者
我的主要设计是这样的:
1、以守护进程的方式运行主程序。
2、主程序根据数据库配置的作业列表,读取作业,产生一个进程去出去,直到最大如5个,就停止再产生进程。
3、如果一个子进程结束了,主程序就监控到,从数据库作业表再读取一个作业,产生一个进程去处理。
4、也就是总是保持5个进程同时运行,结束一个,主程序就再分配任务,产生一个新进程。
5、将运行的过程打到后台的log中,并且主进程终止时,各个子进程也相应跟着终止。

论坛徽章:
0
4 [报告]
发表于 2007-08-25 18:31 |只看该作者
取父进程的PID的函数是getppid(). 你好像写成了getpid().

论坛徽章:
0
5 [报告]
发表于 2007-08-25 19:59 |只看该作者
但我这个的pro*c的运行结果和没有pro*的框架不一样。
没有pro*c的,启动5个子进程,但实际是6六个进程。
第一个是驻留进程,起父pid是1,其他的五个子进程父pid是第一个进程的pid.

但我这个有Pro*c的程序,运行后是5个进程。
没有第一个驻留进程,这5个进程的父pid都是1.。。


我现在在家里,没法调试进一步的结果,明天去公司再发详细。:(

论坛徽章:
0
6 [报告]
发表于 2007-08-25 20:03 |只看该作者
原帖由 scutan 于 2007-8-25 18:31 发表
取父进程的PID的函数是getppid(). 你好像写成了getpid().


但我这个的pro*c的运行结果和没有pro*的框架不一样。
没有pro*c的,启动5个子进程,但实际是6六个进程。
第一个是驻留进程,起父pid是1,其他的五个子进程父pid是第一个进程的pid.

但我这个有Pro*c的程序,运行后是5个进程。
没有第一个驻留进程,这5个进程的父pid都是1.。。


我现在在家里,没法调试进一步的结果,明天去公司再发详细。:(

另外,大侠帮我看看,我的程序还有那些问题,我总觉得好像主进程在作业配置表中无数据,或少于5个任务的情况,会有问题。

因为我是想写一个7*24后台运行的守护进程,在没有作业的情况下,就要等待轮训数据库中的作业配置表,有任务才产生子进程。

论坛徽章:
0
7 [报告]
发表于 2007-08-26 16:26 |只看该作者
程序在 scutan    (冬日夜雨) 的帮助一下,已经基本调试通过

我将继续完善,完善之后将贡献全部的代码。谢谢大家的帮助。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP