Chinaunix首页 | 论坛 | 博客
  • 博客访问: 184827
  • 博文数量: 20
  • 博客积分: 3020
  • 博客等级: 中校
  • 技术积分: 940
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-18 11:01
文章分类

全部博文(20)

文章存档

2011年(2)

2010年(8)

2009年(9)

2008年(1)

我的朋友
最近访客

分类: C/C++

2010-11-21 22:35:44

ACE可以通过如下几个类完成进程的创建、管理和控制。
 1、ACE_Process                   --可移植性地创建和同步进程
 2、ACE_Process_Options           --指定“与平台无关”和“与平台相关”的选项
 3、ACE_Process_Manager           --可移植地创建和同步多组进程
 
 ACE_Process类简介:
    ACE把所有用于进程创建和控制的API都隐藏在ACE_Process包装类中,该类允许程序员派生新的进程,继而等待新进程的终止。通常为每一个新进程使用一个ACE_Process类对象,并且可以为新的子进程设置若干选项:1)设置标准IO句柄;2)指定两个进程间的句柄继承的工作方式;3)设置子进程的环境块和命令行;4)在Windows上指定各种安全属性,或在Unix上设置uid/gid/euid;
    该类提供了以下功能:
    1、创建和终止进程;2、在进程退出时保持同步;3、访问进程属性信息,如进程ID等
    提供的方法有:
    1) prepare()  //子进程创建之前,由spawn()调用,可以对新进程中将要用到的选项进行检测、修改,可方便设置“和平台相关”的选项
    2) spawn()    //创建新的进程地址空间,并运行指定的程序映像
    3) unmanage() //进程退出时,被ACE_Process_Manager调用
    4) getpid()   //返回新子进程的进程ID
    5) exit_code()//返回子进程的退出代码
    6) wait()     //等待创建的进程退出
    7) terminate()//突然终止进程,不给进程清理自己的机会(要慎用)
    只在POSIX/UNIX中有效的方法:
    8) parent()   //可重写,提供“与应用程序相关”的行为;在父进程环境中,若fork()成功创建子进程,此方法将被调用
    9) child()    //可重写,提供“与应用程序相关”的行为;此方法在子进程环境中调用,且在fork()之后,exec()之前
    10)kill()     //向进程发送信号,仅在能向指定进程发送信号的UNIX/POSIX系统中具有可移植性
 ACE_Process_Options类:
    该类提供了以下功能:1)允许应用程序指定需要的“进程控制信息”;2)允许“进程控制项(process control item)”随着平台的改变而扩展
    command_line()    //指定程序的命令和参数,在“被创建进程”中启动新程序时会使用它们
    setenv()          //指定环境变量,并将其添加到被创建进程的环境中
    working_directiory()//指定一个新路径,使被创建进程在启动新程序映像之前切换到这个路径
    set_handles()     //设置某些特殊的文件句柄;被创建进程可被这些进程用于它的STDIN,STDOUT,STDERR
    pass_handle()     //表示一个“应被传递给新创建的进程”的句柄。
 ACE_Process_Manager类:
    可将多个进程作为一个单元来管理:保存内部记录,管理和监视ACE_Process类创建的多组进程;允许一个进程创建一组进程。
    open()          //初始化ACE_Process_Manager
    close()         //释放所有资源(不等待进程退出)
    spawn()         //创建一个进程,将其添加到被管理的一个进程组中
    spawn_n()    //创建n个进程,这些进程都属于同一个进程组
    wait()          //等待进程组中的一些或全部进程退出
    instance()      //返回一个指向ACE_Process_Manager singleton的指针的静态方法
    Unix程序员应该注意,spawn()方法并没有与fork()系统调用类似的语意,而是与大多数Unix系统上都有的system()函数类似,你可以迫使ACE_Process简单地调用fork(),但是在大多数情况下,如果需要,最好能使用ACE_OS::fork()来完成简单的进程分叉;
    使用ACE_Process类创建进程,有两个步骤:
    1、创建一个新的ACE_Process_Options类对象,为新的子进程指定符合你需要的进程属性;
    2、用ACE_Process::spawn()方法创建新的子进程;
    ACE_Process_Options对象负责携带新进程所需要的各个选项。如果需要的话,一个选项对象可以用于多个ACE_Process对象。栈上的ACE_Process对象,代表要创建的新进程。该进程对象会基于传入的选项对象创建新的子进程。spawn()方法在UNIX上使用execvp()函数,在Windows上面会使用CreateProcess()函数。一旦创建了新的子进程,父进程就会调用wait()方法来等待子进程的结束和退出。wait()方法会收集子进程的退出状态,并使得子进程在UNIX系统上不会成为僵尸进程。在Windows系统上,wait()方法会使得CreateProcess()函数创建的进程和线程的HANDLE被关闭。
    ACE_Process类的hook方法:
    1、prepare()挂钩方法:在创建新的子进程之前,ACE_Process::spawn()方法会自动调用进程对象的ACE_Process::prepare()方法,以做一些预先的处理;比如:我们可以检查并修改新进程的选项;要设置针对特定平台的选项,那么这种方法是一种好方法;
    如果prepare()方法返回0,则ACE_Process::spawn()方法会继续运行并创建新的子进程;如果prepare()方法返回-1,那么spawn()方法不会再尝试创建新的子进程;如果在非Windows平台上运行,我们还会设置我们想要子进程在运行时所使用的有效用户ID;
    2、parent(pid_t child)挂钩方法:在fork()函数(UNIX平台)或CreateProcess()函数(Windows平台)被调用之后,这个挂钩方法会立刻在父进程中被回调;
    3、child(pid_t)挂钩方法:在fork()函数完成之后,后续的exec()被调用之前,这个挂钩方法会在子进程中被回调;
    注意:只有在你未在进程选项的创建标记中指定ACE_Process_Options::NO_EXEC标记的情况下,exec()函数才会被调用,这也是默认情况;在Windows平台下,child()方法不会被调用,因为Windows平台上没有fork()和exec()的概念。
    安全参数:
    ACE_Process类对象的安全参数由ACE_Process_Options类的对象指定;
    使用ACE的进程管理器:ACE_Process_Manager类:
    ACE_Process类封装的是一个进程,每次也只能创建、管理一个进程;当药创建一组进程并管理它们的时候,可以使用ACE提供的类ACE_Process_Manager类来完成;这个类允许用户通过单次调用来创建多个子进程,并等待它们的结束、终止和退出;你还可以登记事件处理器,让它们在子进程终止的时候被回调;
    ACE_Process_Manager::spawn()方法与ACE_Process::spawn()方法类似,要使用它们来创建进程,那么必须首先创建一个ACE_Process_Options类的对象option,指定要创建的子进程的各项属性,并把这个类的对象option传递给spawn()方法。通过ACE_Process_Manager::spawn_n()方法,可以一次创建多个子进程。你还可以等待所有的子进程退出,并收集它们的退出状态,同时正确地移除它们所持有的所有资源。此外,你还可以强行终止先前由ACE_Process_Manager创建的进程;
    使用ACE_Process_Manager::创建N个子进程的时候,我们可以等待这N个子进程的退出;当我们调研ACE_Process_Manager::terminate()方法显示地终止一个子进程的时候,这个子进程应该会立刻终止。terminate()方法唯一的一个参数就是你想要终止的进程的进程ID。如果你传入的进程Id是0,那么这个进程管理器就会等待它所管理的任何一个进程退出。在UNIX平台上,可能并不会像我们想象的那样工作良好,而最后收集到的可能并不是我们的进程管理器所管理的进程的退出状态。
    注意:在UNIX系统上,一旦terminate()方法后,ACE_Process_Manager就会发出一个信号终止子进程;你可以通过检查进程的终止状态对此加以观察;
    在这N个子进程中,当完成了对第一个子进程的等待之后,父进程会使用进程管理器又一次执行阻塞式wait()调用,等待余下的所有子进程退出,依次类推,就这样循环,直到最后一个子进程退出为止。为了表明这一要求,我们可以把0超时值传给wait()方法。注意:你还可以指定一个相对的超时时间值,我们的阻塞式等待将在超时后返回。如果等待不成功并发生了超时,那么wait()调用会返回0。
事件处理:
     大多数时候,你会发现,父进程除了等待子进程退出之外,还有很多其它的事情要做,特别是如果你实现的是传统的网络服务器,它会创建很多子进程来完成繁重的网络服务请求;
     为了实现这种用例,ACE_Process_Manager的退出处理方法采用了特定的设计,能够与ACE_Reactor框架协同工作,以让Reactor框架在进程终止时调用终止回调处理器;
     要实现进程的终止回调处理器,我们必须为ACE_Event_Handler类实现一个子类,然后让这个子类作为进程的终止回调处理器;比如:我们实现的终止回调处理器类为ExitHandler,并在ExitHandler类中实现一个终止处理方法handle_exit(ACE_Process *lpProcess);参数是一个指向ACE_Process类对象的指针lpProcess,它代表刚刚退出的进程。当进程退出的时候,反应器会同步地调用事件处理器的handle_exit()方法,并把一个ACE_Process类对象的指针传递进来。
     在底层发生的事情是:
     1、在POSIX平台上,ACE_Process_Manager为接收SIGCHLD信号做了登记,在接收到该信号的时候,ACE_Process_Manager使用反应器的通知机制在正常的进程上下文中重新获取控制;
     2、在Windows平台上,ACE_Process_Manager向反映器做了登记,以通过Reactor框架接收进程句柄上的事件通知。因为只有ACE_WFMO_Reactor反映器实现了支持句柄上的事件通知功能,如果你在Windows平台上换用了其它的反映器,子进程的退出通知功能就无法工作;
     当ACE_Process_Manager收到通知、并被告知子进程已经退出时,它会调用终止处理器ExitHandler的handle_exit()方法,进行终止处理;
     使用ACE_Process_Mutex进行同步:
     要对线程进行同步,需要使用线程同步原语,比如:互斥体或信号量。当在不同的进程中执行时,线程是在不同的地址空间中运行的。对这样的线程进行同步变得有一点困难。在这样的情况下,你可以使用下面的任意一种方法:
     1、在共享内存中创建你需要使用的同步原语,设置适当的选项,确保它们能在进程间正常工作;
     2、使用作为ACE库的一部分提供的特殊的进程同步原语;
     ACE提供的ACE_Process_Mutex类,它可以确保运行在不同进程中的线程之间的同步;ACE提供的ACE_Process_Mutex类是一个命令互斥体,可以跨越多个地址空间使用;因为互斥体是有名称的,通过把相同的名称传入ACE_Process_Mutex的构造器,你可以重新创建代表同一个互斥体的对象;
     对于UNIX用户来说,ACE_Process_Mutex对应着System V信号量。与大多数资源不同,这些信号量不会在对它的引用全部都已经销毁时自动释放。因此,在使用这个类的时候要特别小心,要确保ACE_Process_Mutex的析构器被调用,即使在非正常退出的情况下。UNIX用户的另外一种选择是ACE_SV_Semaphore_Complex,它会自动进行引用计数,一旦引用它的所有进程全部退出,它就会自动移除互斥体。如果除了最后一个进程,其它进程在退出时没有适当地关闭互斥体(不管是有意还是无意),上述的自动引用计数/移除过程也能正常工作;
    关于ACE_Process类的例子:
#include "ace/Log_Msg.h"
#include "ace/Process.h"
#include "ace/OS.h"
class Manager: public ACE_Process
{
 private:
  ACE_TCHAR strProgramName[64];
 public:
  Manager(const ACE_TCHAR* strProgramName)
  {
   ACE_DEBUG( (LM_DEBUG, ACE_TEXT("Manager::Manager()\n")) );
   ACE_OS::memset(this->strProgramName, 0, sizeof(this->strProgramName));
   ACE_OS::strcpy(this->strProgramName, strProgramName);
  }
  int doWork(void)
  {
   int nReturn = 0;
   ACE_DEBUG( (LM_DEBUG, ACE_TEXT("Manager::doWork()\n")) );
   //declare a ACE_Process_Options object options;
   ACE_Process_Options options;
   options.command_line(ACE_TEXT("calc"));
   //create an new process with options;
   pid_t pid = this->spawn(options);
   if(pid < 0)
   {
    ACE_DEBUG( (LM_ERROR, ACE_TEXT("failed to create sub process[%d]:%p\n"), pid, ACE_TEXT("spawn")) );
    return -1;
   }
   ACE_DEBUG( (LM_DEBUG, ACE_TEXT("spawn child: %d\n"), pid) );
   //wait for my child to exit
   nReturn = this->wait();
   if(nReturn < 0)
   {
    ACE_DEBUG( (LM_ERROR, ACE_TEXT("failed to wait[%d]\n"), nReturn, ACE_TEXT("wait")) );
    return -2;
   }
   return 0;
  }
  int prepare(ACE_Process_Options& options)
  {
   ACE_DEBUG( (LM_DEBUG, ACE_TEXT("ACE_Process::prepare\n")) );
   return 0;
  }
  void parent(pid_t child)
  {
   ACE_DEBUG( (LM_DEBUG, ACE_TEXT("parent(child): %d\n"), child) );
  }
  void child(pid_t parent)
  {
   ACE_DEBUG( (LM_DEBUG, ACE_TEXT("child(parent): %d\n"), parent) );
  }
};

int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
 Manager m("GET_PROCESS");
 m.doWork();
 return 0;
}
关于ACE_Process_Manager类的例子:
#include "ace/Log_Msg.h"
#include "ace/Process_Manager.h"
#include "ace/OS.h"
static const int NCHILDREN = 3;
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
 ACE_Process_Manager* pm = NULL;
 pm = ACE_Process_Manager::instance();
 //set sub process command
 ACE_Process_Options options;
 options.command_line(ACE_TEXT("ping 10.10.3.238 -c 5"));
 //create sub process
 pid_t pids[NCHILDREN];
 pm->spawn_n(NCHILDREN, options, pids);
 ACE_OS::sleep(1);
 pm->terminate(pids[0]);
 //wait for all the processes exit;
 ACE_exitcode exitcode;
 for(int i = 0; i < NCHILDREN; i++)
 {
  ACE_DEBUG( (LM_DEBUG, ACE_TEXT("wait for sub [%d]process %d exit ......\n"), i, pids[i]) );
  pm->wait(pids[i], &exitcode);
  ACE_DEBUG( (LM_DEBUG, ACE_TEXT("[%d]process %d exit with code %d\n"), i, pids[i], exitcode) );
 }
 getchar();
 return 0;
}
阅读(773) | 评论(1) | 转发(0) |
0

上一篇:sprintf用法解析

下一篇:NTP的基础知识

给主人留下些什么吧!~~

chinaunix网友2010-11-22 17:28:09

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com