多进程编程学习

  • Posted on
  • by

计算机的cpu越来越廉价,在一些需要大量计算的公司和科研单位,集成机器(cluster)也变得很普遍。这就会引出了一个问题,怎么安排任务才能让这么多cpu得到充分的利用?这个问题其实早就有人考虑到了, PBS就是用来批量提交任务的程序。PBS功能强大,但是未必就能够满足所有要求。

要编写个性化的进程管理程序需要了解在Lunix/unix下面已经包括了的进程编程所需要的库函数。简单的说,首先可以通过fork()函数生成子进程。调用fork()后会有两个返回,子进程如果成功生成会返回0,父进程返回的是PID。然后可以调用exec族函数,将子进程替换成所要执行的程序。进程在执行完后并会留下僵尸(zombie)进程,可以使用wait()函数返回执行情况并完全释放资源。关于进程编程有一个完整的教程----《系统调用跟我学:1234》。

以下这个小程序展示如何生成一个进程,执行任务,并且当任务完成后捕捉到子进程的信息。

/* One process program */
/* This sample shows how to use fork(),execlp() and waitpid() */
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
main()
{

    pid_t pc, pr;
    pc=fork();
    if(pc<0)        
        printf("Error occured on forking.\n");
    else if(pc==0){     /* open /etc/hosts with nedit */        
        execlp("nedit", "nedit","/etc/hosts", NULL);    
        exit(0);
    }

    do{
        pr=waitpid(pc, NULL, WNOHANG);  
        if(pr==0){          
            printf("No child exited\n");
            sleep(1);
        }
    }while(pr==0);  

    if(pr==pc)
        printf("successfully get child %d\n", pr);
    else
        printf("some error occured\n");

}
对于多个进程的情况,还需要学习关于信号的知识。因为进程一旦调用了wait,就立即阻塞自己。而采用信号处理程序(signal handler)就能够避开这个缺点。关于信号处理可以参考《Introduction To Unix Signals Programming》,关于多进程编程可以参考《Unix Multi-Process Programming and Inter-Process Communications (IPC)》。 下面这个程序展示了如何产生两个进程,在二十秒之内有进程退出后就提交指定任务。
/* multi process program */
/* This sample shows how to fork two procss */
/* and submit new task once there is task finished */
/* in a period of time */

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

void catch_child(int sig_num)
{
    int child_status;
    pid_t pc, pr;
    pr=wait(&child_status);
    printf("child %d exited.\n",pr);
    pc=fork();
    if(pc<0)        
        printf("Error occured on forking.\n");
    else if(pc==0){     /* open /etc/hosts with nedit */        
        execlp("nedit", "nedit","/etc/hosts", NULL);    
        exit(0);
    }
}


main()
{
    signal(SIGCHLD, catch_child);
    int child_pid[2];
    int i,j;
    for(j=0;j<2;j++){       /* generates two child-process */
    child_pid[j] = fork();
    switch (child_pid[j]) {
            case -1:       
            perror("fork");
            exit(1);
            case 0:        
            printf("hello world\n");
            sleep(5);    /* sleep a little, so we'll have */
                             /* time to see what is going on  */
            exit(0);
            default:       
            break;
    }
    }

    for (j=0; j<20; j++) {
        printf("%d\n", j);
        sleep(1);    /* sleep for a second, so we'll have time to see the mix */
    }
}