ACE进程管理

来源:互联网 发布:阿里云 ecs 数据库 编辑:程序博客网 时间:2024/05/29 07:25

ACE把所有用于进程创建和控制的API都隐藏在ACE_Process包装类中.这个类允许程序员派生新的进程,继而等待新进程的终止.你通常会为每一个新进程使用一个ACE_Process类的对象,并且可以为新的子进程设置若干选项:
1、设置标准IO句柄;
2、指定两个进程间的句柄继承的工作方式;
3、设置子进程的环境块和命令行;
4、在Windows上指定各种安全属性,或在Unix上设置uid/gid/euid;
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()的概念;

4、 unmanage()挂钩方法:当ACE_Process_Manager管理的进程退出时,被ACE_Process_Manager调用。


安全参数 :
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::spawn_n()创建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类的例子:

 

[c-sharp] view plaincopyprint?
  1. #include "ace/Log_Msg.h"  
  2. #include "ace/Process.h"  
  3. #include "ace/OS.h"  
  4. #include "ace/Process_Manager.h"   
  5. class ChildProcess: public ACE_Process  
  6. {  
  7. public:  
  8.     ChildProcess()  
  9.     {  
  10.         ACE_DEBUG( (LM_DEBUG, ACE_TEXT("ChildProcess::ChildProcess()/n")) );  
  11.     }  
  12.     int prepare(ACE_Process_Options& options)  
  13.     {  
  14.         ACE_DEBUG( (LM_DEBUG, ACE_TEXT("ACE_Process::prepare/n")) );  
  15.         return 0;  
  16.     }  
  17.     void parent(pid_t child)  
  18.     {  
  19.         ACE_DEBUG( (LM_DEBUG, ACE_TEXT("parent(child): %d/n"), child) );  
  20.     }  
  21.     void child(pid_t parent)  
  22.     {  
  23.         ACE_DEBUG( (LM_DEBUG, ACE_TEXT("child(parent): %d/n"), parent) );  
  24.     }  
  25.     void unmanage()  
  26.     {  
  27.         ACE_DEBUG( (LM_DEBUG, ACE_TEXT("ACE_Process::unmanage/n")) );  
  28.     }  
  29. };  
  30.   
  31. int ACE_TMAIN(int argc, ACE_TCHAR** argv)  
  32. {  
  33.       
  34.     //child proecss   
  35.     if (argc >1)  
  36.     {  
  37.         ACE_DEBUG( (LM_DEBUG, ACE_TEXT("spawn child: %d/n"), getpid()) );  
  38.         return 0;  
  39.     }  
  40.     int nReturn = 0;  
  41.     ChildProcess child;  
  42.     //declare a ACE_Process_Options object options;  
  43.     ACE_Process_Options options;  
  44.     options.command_line(ACE_TEXT ("%s a"), argv[0]);  
  45.     //create an new process with options;  
  46.       
  47.     pid_t pid = ACE_Process_Manager::instance()->spawn(&child,options);  
  48.     if(pid < 0)  
  49.     {  
  50.         ACE_DEBUG( (LM_ERROR, ACE_TEXT("failed to create sub process[%d]:%p/n"), pid, ACE_TEXT("spawn")) );  
  51.         return -1;  
  52.     }  
  53.       
  54.     //wait for my child to exit   
  55.     nReturn = ACE_Process_Manager::instance()->wait();  
  56.     if(nReturn < 0)  
  57.     {  
  58.         ACE_DEBUG( (LM_ERROR, ACE_TEXT("failed to wait[%d]/n"), nReturn, ACE_TEXT("wait")) );  
  59.         return -2;  
  60.     }  
  61.     return 0;  
  62. }  
 

 

运行结果:

 

关于ACE_Process_Manager类的例子:

 

[c-sharp] view plaincopyprint?
  1. #include "ace/Log_Msg.h"  
  2. #include "ace/Process_Manager.h"  
  3. #include "ace/Reactor.h"   
  4. static const int NCHILDREN = 2;  
  5. // Listing 1 code/ch10   
  6. class DeathHandler: public ACE_Event_Handler  
  7. {  
  8. public:  
  9.   DeathHandler () : count_(0)  
  10.   {  
  11.     ACE_TRACE (ACE_TEXT ("DeathHandler::DeathHandler"));  
  12.   }  
  13.   virtual int handle_exit (ACE_Process * process)  
  14.   {  
  15.     ACE_TRACE (ACE_TEXT ("DeathHandler::handle_exit"));  
  16.     ACE_DEBUG  
  17.       ((LM_DEBUG,  
  18.         ACE_TEXT ("Process %d exited with exit code %d/n"),  
  19.         process->getpid (), process->return_value ()));  
  20.     if (++count_ == NCHILDREN)  
  21.       ACE_Reactor::instance ()->end_reactor_event_loop ();  
  22.     return 0;  
  23.   }  
  24. private:  
  25.   int count_;  
  26. };  
  27. // Listing 1   
  28. // Listing 0 code/ch10   
  29. int ACE_TMAIN (int argc, ACE_TCHAR *argv[])  
  30. {  
  31.     if (argc > 1) {      // Running as a child.  
  32.         ACE_DEBUG  
  33.             ((LM_DEBUG,  
  34.             ACE_TEXT ("Process %d /n"),getpid ()));  
  35.         return 0;  
  36.     }  
  37.   // Instantiate a process manager with space for  
  38.   // 10 processes.   
  39.   ACE_Process_Manager pm (10, ACE_Reactor::instance ());  
  40.   // Create a process termination handler.  
  41.   DeathHandler handler;  
  42.   // Specify the options for the new processes to be spawned.  
  43.   ACE_Process_Options options;  
  44.   options.command_line (ACE_TEXT ("%s a"), argv[0]);  
  45.   // Spawn two child processes.  
  46.   pid_t pids[NCHILDREN];  
  47.   pm.spawn_n (NCHILDREN, options, pids);  
  48.   // Register handler to be called when these processes exit.  
  49.   for (int i = 0; i < NCHILDREN; i++)  
  50.     pm.register_handler (&handler, pids[i]);  
  51.   // Run the reactor event loop waiting for events to occur.  
  52.   ACE_Reactor::instance ()->run_reactor_event_loop ();  
  53.   return 0;  
  54. }  
  55. // Listing 0  

 

运行结果: