日期:2014-05-16  浏览次数:20619 次

Linux 进程函数入门

?

?????? 这里进程的概念就不介绍了。首先介绍fork函数的用法.

?????? fork函数位于unistd.h,Linux对应的进程库位于/sys/types.h中,他提供了pid_t这样的结构体。fork函数被调用到的时 候,被创建的子进程会得到与父进程虚拟地址空间相同但是独立的一份拷贝,包括数据、文本等等,甚至会获得与父进程任何打开文件描述符相同的拷贝。fork 函数调用一次,但返回两次。第一次返回给父进程,返回的值是子进程的pid;第二次在子进程中,返回0。以下的代码清楚的说明了上述情况:

?????? 第一个公用文件:csapp.h

?

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
pid_t Fork(void){
   pid_t pid;
   if((pid=fork())<0){
	   printf("Fork error");
   }
   return pid;
}

?

??? 第二个是示范程序test.c:

?

#include "csapp.h"
int main(){
    int x=1;
    pid_t pid = Fork();
    if(pid==0){
        printf("printf1 x=%d\n",++x);
    }
    printf("printf2 x=%d\n",--x);
    exit(0);
}

?

? 这个程序在运行的时候会按照fork函数的调用方式返回:

?

printf2 x=0   //父进程的输出
printf1 x=2  //子进程的输出
printf2 x=1 ? //子进程的输出

?

?? 至于这里为什么父进程优先执行完毕,完全取决于对应的Linux系统的进程调度的实现方式。

?

??? 其次是waitpid()函数,它的函数声明如下所示:

?

pid_t waitpid(pid_t pid,int *status,int options)

??? 这个函数有三个参数,第一个参数为等待集合的成员,如果pid>0,则为等待的某一个单独进程,它的进程ID等于pid,如果pid=-1,则表明要等待所有在该进程上创建的子进程。

?? 第二个参数是waitpid函数会用来存放关于进程存放的状态信息。

?? 第三个参数是用来规范waitpid函数的行为,默认为WHOHANG(0),表示如果等待集合中的任何子进程都还没有终止,那么就立即返回。

?? 这个函数返回导致该函数返回的已终止的子进程的PID。

?

?

#include "../process/csapp.h"
#define N 2
int main(){
    pid_t pid[N];
    pid_t reapid;
    int status,i;
    int index=0;
    for(i=0;i<N;i++){
        if((pid[index++]=Fork())==0){
        	exit(100+i);//子进程一创建,就立即退出了
        }
    }
    int j;
    //由于这段代码只会由父进程调用到
    //所以这个pid数组存放的是子进程的PID信息
    for(j=0;j<index;j++){
    	printf("pid[%d]=%d\n",j,pid[j]);
    }
    i=0;
    //waitpid返回导致wait函数退出的pid进程号
    while((reapid=waitpid(pid[i++],&status,0))>0){
         if(WIFEXITED(status)){
        	 printf("child %d normally exit with %d\n",reapid,WEXITSTATUS(status));
         }else{
        	 printf("child %d exit abnormal\n",reapid);
         }
    }
    if(errno!=ECHILD){
    	printf("waitpid error");
    }
    exit(0);
}

?

?? 这里用到了一点小技巧,在父进程里保存了所有创建的子进程的信息,并有序的终止子进程。程序的输出是:

?

pid[0]=2525
pid[1]=2526
child 2525 normally exit with 100
child 2526 normally exit with 101

?

? 最后介绍下linux里关于进程非本地跳转的入门知识

? 非本地跳转指的是将控制从一个函数转移到一个当前正在执行的函数,而不需要进行正常的函数调用-返回序列.这样就涉及到两个函数:

?

#include <setjmp.h>
//在env缓冲区中保存当前调用环境,以供后面longjmp调用
//调用环境包括程序计数器、栈指针、通用目的寄存器
int setjmp(jmp_buf env)      //可以看成是catch语句块
//从env缓冲区恢复调用环境,然后触发一个从最近一次初始env的setjmp调用的返回,
//然后setjmp返回,返回值是retval
void longjmp(jmp_buf env,int retval)  //可以看成是throw语句块
 
//她们的扩展版本是sigsetjmp和longjmp 这是可以被信号处理的版本

?

? 例子程序如下:

?

#include "../process/csapp.h"
#define N 2
sigjmp_buf buf;
void handler(int sig){
	//longjmp看成是throw语句块
	siglongjmp(buf,2);
}
int main(){
	signal(SIGINT,handler);
	//这里可以把setjmp看成是try...catch里的catch语句块
	if(!sigsetjmp(buf,1)){
		printf("starting\n");
	}else{
		printf("restarting");
	}
	while(1){
		sleep(1);
		printf("processing\n");
	}
	exit(0);
}

?

这个函数运行的输出结果是:

starting
processing
processing
processing
processing
restarting
....
?