一、fork()函数(父进程创建子进程)
一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
1、父进程复制出子进程中,父进程返回值为子进程的pid;
2、父进程复制出子进程中,子进程返回值为0;
3、父进程复制出子进程中,如果出现错误,fork返回一个负值;
我们用代码来模拟一下这个过程:
#include
#include
#include
#include
#include
int main(int argc,char* argv[],char* envp[])
{
int i = 0;
for(;i < 2;i++)
{
pid_t pid = fork();
printf("A");
}
exit(0);
}
fork()函数的特点:
1)fork函数在复制时,会将父进程的文件描述符全部都复制过去;
2)fork函数在复制时,若父进程有锁,则两个进程不会共用一把锁,但是子进程会复制过去父进程锁的状态;
3)fork函数在复制时,会将父进程的缓冲区的内容也复制,如上方代码执行后会打印出8个A;
二、exec()函数(替换进程函数)
fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
1)所需头文件:
#include
2)函数原型:
int execl(const char *pathname, const char *arg, ...)
int execv(const char *pathname, char *const argv[])
int execle(const char *pathname, const char *arg, ..., char *const envp[])
int execve(const char *pathname, char *const argv[], char *const envp[])
int execlp(const char *filename, const char *arg, ...)
int execvp(const char *filename, char *const argv[])
函数返回值:
成功:函数不会返回
出错:返回-1,失败原因记录在error中
同样使用代码:
#include
#include
#include
#include
#include
int main(int argc,char* argv[],char*envp[])
{
printf("exec pid = %d\n",getpid());
pid_t pid = fork();
assert(pid != -1);
/*
if(pid == 0)
{
char* myargv[] = {"b","hello","abc","123",(char*)0};
char* myenvp[] = {"MYSTR=hello",,"VAL=100",(char*)0};
// execl("./b","b","hello","abc","123",(char*)0);
execve("./b",myargv,myenvp);
perror("execl error");
}
*/
/*
if(pid == 0)
{
execl("/bin/ps","-f",(char*)0);
perror("execl error");
exit(0);
}
wait(NULL);
printf("main error\n");
*/
// execl("/bin/ps","ps","-ef",(char*)0);
execlp("ps","ps","-f",(char*)0);
// execlp("/bin/ps","ps","-f",(char*)0,envp);
// char* myargv[] = {"ps","-f",(char*)0};
// execv("/bin/ps",myargv);
// execvp("ps",myargv);
execve("/bin/ps",myargv,envp);
if(errno = ENOENT)
{
perror("execl error");
}
/*
char * ls_argv[] = {"main", "-a", NULL};
if(fork() == 0)
{
// if(execv("/bin/ls", ls_argv) < 0)
if(execv("/home/ws/cy1706/jiaobeng/main", ls_argv) < 0)
{
perror("execl error");
}
}
*/
exit(0);
}
代码中将子进程替换成一些ls或ps系统命令。