函数原型: int system(const char * string); 参数说明: string:命令 int:返回值 =-1:出现错误 =0:调用成功但是没有出现子进程 >0:成功退出的子进程的id(=127表示system()在调用/bin/sh时失败)
【替换进程映像】
exec家族一共有六个函数,分别是:
int execl(const char *path, const char *arg0, ...... ,(char*)0); int execlp(const char *file, const char *arg0, ......,(char*)0); int execle(const char *path, const char *arg0, ......,(char*)0,char * const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char * const argv[]); int execve(const char *filename, char *const argv[], char *const envp[]);1,其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
2,几个字母:
"l"代表 list即表示以list形式给出,但最后要加一个空指针,如果用常数0来表示空指针,则必须将它强行转换成字符指针,否则有可能出错。
"v"代表 vector即矢量,
"p"代表通过PATH环境变量来查找新程序的可执行文件路径,
"e"代表可以传入一个环境变量envp。
3,示例程序:
char *argv[]={“ls”,”-l”,(char *)0} //先定义一个指针数组 if (execv(“/bin/ls”,argv)) < 0) { perror(“execl error!”); }
#include <unistd.h> main() { char * const ps_argv[]={"ps","-ux",(char*)0}; char * const ps_envp[]={"PATH=/bin:/usr/bin","TERM=console",(char*)0}; //以下任选一种 execl("/bin/ps","ps","-ux",(char*)0); execlp("ps","ps","-ux",(char*)0); execle("/bin/ps","ps","-ux",(char*)0,ps_envp); execv("/bin/ps",ps_argv); execvp("ps",ps_argv); execve("/bin/ps",ps_argv,ps_envp); printf("Done.\n");//不会被执行,因为替换后不再返回到原函数中 }执行替换后不再返回到原程序。
【复制进程映像】
http://blog.csdn.net/jason314/article/details/5640969
由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。
函数原型: pid_t fork( void); 参数说明 pid_t:返回值,成功 ==> 父进程:返回子进程id ==> 子进程:返回0 失败 ==> 返回-1常用程序结构:
#include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <stdio.h> int main() { pid_t pid; printf("fork()"); //printf("fork()\n"); pid=fork(); switch (pid) { case -1:/* error */ perror("fork error\n"); exit(1); case 0:/* child */ printf("child ppid:%4d pid:%4d return:%4d\n",getppid(),getpid(),pid); break; default:/* father */ printf("father ppid:%4d pid:%4d return:%4d\n",getppid(),getpid(),pid); break; } exit(0); }
#./fork2 #printf("fork()"); fork()child ppid:17960 pid:17961 return: 0 fork()father ppid:1084 pid:17960 return:17961、 #./fork2 #printf("fork()\n"); fork() child ppid:17923 pid:17924 return: 0 father ppid:1084 pid:17923 return:17924这就跟printf的缓冲机制有关了, printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上。但是,只要看到有/n 则会立即刷新stdout,因此就马上能够打印了。
vfork创建新进程的主要目的在于用exec函数执行另外的程序,实际上,在没调用exec或exit之前子进程的运行中是与父进程共享数据段的。在vfork调用中,子进程先运行,父进程挂起,直到子进程调用exec或exit,在这以后,父子进程的执行顺序不再有限制。
fork与vfork的区别:
fork | vfork |
子进程拷贝父进程的数据段,代码段 | 子进程与父进程共享数据段 |
父子进程的执行次序不确定 | 证子进程先运行,在调用exec 或exit 之前与父进程数据是共享的, 在它调用exec或exit 之后父进程才可能被调度运行。 |
vfork()保证子进程先运行,在她调用exec 或exit 之后父进程才可能被调度运行。 如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。 |
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { pid_t pid; int cnt = 0; pid = vfork(); switch (pid) { case -1:/* error */ perror("vfork error\n"); exit(1); case 0:/* child */ cnt++; printf("cnt=%d\n",cnt); printf("child ppid:%4d pid:%4d return:%4d\n",getppid(),getpid(),pid); _exit(0); break; default:/* father */ cnt++; printf("cnt=%d\n",cnt); printf("father ppid:%4d pid:%4d return:%4d\n",getppid(),getpid(),pid); break; } exit(0); }结果:
#./vfork cnt=1 child ppid:24884 pid:24885 return: 0 cnt=2 father ppid:1084 pid:24884 return:24885网上抄的一段,可以再理解理解:
函数原型: pid_t wait (int * status); 参数说明: status:子进程的结束状态值会由参数status 返回 pid_t:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno 中进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。
该函数我的理解是:为了避免出现僵尸进程(即父进程没有wait读取子进程的退出信息)
#include<sys/types.h> #include<unistd.h> #include<stdio.h> #include<sys/wait.h> #include<stdlib.h> int main() { pid_t pid; char * message; int n; int exit_code; pid = fork(); switch(pid) { case -1 : perror("fork failed!\n"); exit(1); case 0: message = "this is the child"; n=5; exit_code=37; break; default: message = "this is the parent"; n=3; exit_code=0; break; } for(;n>0;n--){ puts(message); sleep(1); } //这里为了防止在退出时父进程先退出导致子进程成为僵尸进程,用wait if (pid != 0){ int stat_val; pid_t child_pid = wait(&stat_val); printf("child has finished :PID=%d\n",child_pid); if (WIFEXITED(stat_val)) printf("child exited with code %d\n",WEXITSTATUS(stat_val)); else printf("child terminated abnormally\n"); } exit(exit_code); }
函数原型: pid_t waitpid(pid_t pid,int * status,int options); 参数说明: pid<-1 等待进程组识别码为pid 绝对值的任何子进程。 pid=-1 等待任何子进程,相当于wait()。 pid=0 等待进程组识别码与目前进程相同的任何子进程。 pid>0 等待任何子进程识别码为pid 的子进程。 status:子进程的结束状态值会由参数status返回。 pid_t:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回 -1。失败原因存于errno 中。
常用结构:
//设置等待子进程,且父进程不阻塞 waitpid(child_pid,(int*)0,WNOHANG)
WNOHANG表示非阻塞调用。
xxx
头文件: include<unistd.h> 函数原型: pid_t getpgrp(void); 说明: getpgrp用来取得目前进程所属的组识别码。 此函数相当于调用getpgid(0);返回目前进程所属的组识别码。
头文件: include<unistd.h> 函数原型: pid_t getpgid( pid_t pid); 参数说明: pid:指定进程号 pid_t:返回值,执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中(错误代码ESRCH表示找不到符合参数pid指定的进程)。 说明: getpgid用来取得参数pid指定进程所属的组识别码。 如果参数pid为0,则会取得目前进程的组识别码。
头文件: include<unistd.h> 函数原型: int setpgid(pid_t pid,pid_t pgid); 参数说明: setpgid将参数pid指定进程所属的组识别码设为参数pgid指定的组识别码。 如果参数pid 为0,则会用来设置目前进程的组识别码。 如果参数pgid为0,则由pid指定的进程ID将用作进程组ID。 返回值: 执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。 错误代码 EINVAL 参数pgid小于0。 EPERM 进程权限不足,无法完成调用。 ESRCH 找不到符合参数pid指定的进程 说明: 一个进程只能为它自己或它的子进程设置进程组ID。
头文件: include<unistd.h> 函数原型: pid_t getsid( void ); 说明: 返回当前进程会话组id
头文件: include<unistd.h> 函数原型: pid_t setsid( void ); 说明: setsid函数将创建新的会话,并使得调用setsid函数的进程成为新会话的领头进程。调用setsid函数的进程是新创建会话中的惟一的进程组,进程组ID为调用进程的进程号。setsid函数产生这一结果还有个条件,即调用进程不为一个进程的领头进程。