封装fork/wait等操作, 编写函数 process_create(pid_t* pid, void* func, void* arg), func回调函数就是子进程执行的入口函数, arg是传递给func回调函数的参数.
#include<stdio.h>
#include<unistd.h>
void Func(char* arg){
printf("%s,child is : %d father is %d",arg,getpid(),getppid());
sleep(5);
return;
}
void process_creat(int* pid,void* Func,char* arg){
pid_t id;
*pid = fork();
if (*pid<0){
perror("");
return;
}
//子进程
else if (*pid==0){
//因为Func为void* 类型的函数,所以首先要将Func()转化为(void(*)(char*))类型
void(*p)(char*) = (void(*)(char*))Func;
(*p)(arg);
}
else{
//父进程阻塞等待
id=waitpid(-1,NULL,0);
printf("child wait success pid :%d",id);
return;
}
}
int main(){
pid_t pid;
process_creat(&pid,Func,"hello world");
}
popen:
#include <stdio.h> FILE *popen(const char *command, const char *type); int pclose(FILE *stream);
popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程。这个管道必须由pclose()函数关闭,而不是fclose()函数。pclose()函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。如果shell不能被执行,则pclose()返回的终止状态与shell已执行exit一样。
1.type参数只能是读或者写中的一种,得到的返回值(标准I/O流)也具有和type相应的只读或只写类型。如果type是"r"则文件指针连接到command的标准输出;如果type是"w"则文件指针连接到command的标准输入。
2.command参数是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并使用-c标志,shell将执行这个命令。
3. popen()的返回值是个标准I/O流,必须由pclose来终止。前面提到这个流是单向的(只能用于读或写)。向这个流写内容相当于写入该命令的标准输入,命令的标准输出和调用popen()的进程相同;与之相反的,从流中读数据相当于读取命令的标准输出,命令的标准输入和调用popen()的进程相同。
4.返回值:如果调用fork()或pipe()失败,或者不能分配内存将返回NULL,否则返回标准I/O流。popen()没有为内存分配失败设置errno值。如果调用fork()或pipe()时出现错误,errno被设为相应的错误类型。如果type参数不合法,errno将返回EINVAL。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 int main(){
5 FILE* fp=NULL;
6 char buf[10240]={0};
7 fp=popen("ls -al","r");
8 if(fp==NULL){
9 return -1;
10 }
11 fread(buf,10240,1,fp);
12 printf("%s\n",buf);
13 pclose(fp);
14 return 0;
15 }
缺点:使用popen的不好影响是,针对每个popen调用,不仅要启动一个被请求的程序,还要启动一个shell,即每个popen调用将多启动两个进程
system:
system()函数调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell,比如bash,-c选项是告诉shell从字符串command中读取命令;在该command执行期间,SIGCHLD是被阻塞的,好比在说:hi,内核,这会不要给我送SIGCHLD信号,等我忙完再说;在该command执行期间,SIGINT和SIGQUIT是被忽略的,意思是进程收到这两个信号后没有任何动作
返回值:
为了更好的理解system()函数返回值,需要了解其执行过程,实际上system()函数执行了三步操作:
1.fork一个子进程;
2.在子进程中调用exec函数去执行command;
3.在父进程中调用wait去等待子进程结束。
对于fork失败,system()函数返回-1。
如果exec执行成功,也即command顺利执行完毕,则返回command通过exit或return返回的值。
1 int system(char* command){
2
3 int pid;
4 int status;
5
6 if(command==NULL){
7
8 //当command为空时返回非零值
9 return 1;
10
11 }
12 if(pid=fork()<0){
13
14 //创建子进程失败的话返回 -1;
15 status=-1;
16
17 }else if(pid=fork()==0){
18
19 //exec函数足中的程序替换
20 execl("/bin/sh","sh","-c",command,NULL);
21 _exit(127);
22
23 }else{
24
25 //设置为阻塞状态
26 while(waitpid(pid,&status,0)<0){
27 if(errno!=EINTR ){
28 status=-1;
29 break;
30 }
31 }
32 }
33
34 return status;
35
36 }
end;