fork
出来的子进程创建子进程,本质是多了一个进程;多了一个进程是多了一套进程相关的数据结构。
int main()
{
const char* str ="hello world\n";
fork();//父进程调用fork
//子进程只会执行后面的代码
while(1)
{
printf(" pid: %s,ppid: %s, str:%s\n",getpid(),getppid(),str);
sleep(1);
}
return 0;
}
int main()
{
const char* str ="hello world\n";
pid_t ret = fork();//父进程调用fork
//子进程只会执行后面的代码
if(ret==0)
{
while(1)
{
printf("child: pid: %s,ppid: %s, str:%s\n",getpid(),getppid(),str);
sleep(1);
}
}
else if(ret>0)//返回子进程的PID
{
while(1)
{
printf("father: pid: %s,ppid: %s, str:%s\n",getpid(),getppid(),str);
sleep(1);
}
}
else
{
perror("fork");
}
return 0;
}
#include
#include
int main()
{
for(int i=0;i<135;++i)
{
printf("[%d]:%s\n",i,strerror());
}
return 0;
}
man 2/3 exit
站在操作系统角度,理解终止进程,核心思想:
- C语言也是有内存清理资源的函数。
pid_t wait ( int* status );
父进程调用等待。
status
:操作系统在PCB里面存着的退出码(比特位第15位到第8位),需要 (status>>8) & 0xFF
获得status
:如果传递NULL
,表示不关心子进程的退出状态信息。#include
#include
#include
#include
#include
int main()
{
pid_t id = fork();
if(id == 0)
{
int count=5;
while(count)
{
printf("child: i am running %d, ppid: %d, pid: %d\n",count--,getppid(),getpid());
sleep(1);
}
printf("child: i quit....\n");
exit(10);
}
else
{
printf("father is waiting:\n");
int status =0;
pid_t ret = wait(&status);
printf("father waited done :exit num: %d, ret: %d\n",(status>>8) & 0xFF,ret);//拿到 status 的第15 - 8的比特位
printf("father quit ...\n");
}
//if(ret == -1)...
return 0;
}
pid_ t waitpid ( pid_t pid , int * status, int options);
options
:OS在PCB存着的退出信号:kill -num
;
waitpid
;退出信号存放在status
的比特位第6位到第0位,通过status & 0X7F
获得WNOHANG
,表示采用非阻塞等待轮询探测调用 waitpid
;WNOHANG
:pid指定的子进程没有结束,则waitpid()
函数返回0,不予以等待;父进程继续去做别的事情。waitpid()
返回该子进程的ID。pid
:Pid=-1
,等待任一个子进程,与wait等效。
Pid>0
.等待其进程ID与pid相等的子进程。WNOHANG
,而调用中waitpid
发现没有子进程可收集,则返回0;//childe
pid_t id = fork();
if(id == 0)
{
int count=5;
while(count)
{
printf("child: i am running %d, ppid: %d, pid: %d\n",count--,getppid(),getpid());
sleep(1);
}
printf("child: i quit....\n");
exit(10);
}
//father
int status =0;
pid_t ret = waitpid(-1,&status,0);
if(ret >0 && WIFEXITED(status)== 0)
{
printf("wait sucess quit normal !\n");
printf("exit code: %d,quit signal: %d, pid: %d\n",WEXITSTATUS(status),WIFEXITED(status),ret);
}
else{
printf("wait failed child quit kill signal:%d\n", WIFEXITED(status));//推出信号
}
status的系统提供的使用方法
WIFEXITED(status)
: 若为正常终止子进程,WIFSIGNALED(status)
终止信号返回 0。若信号 为非0,表明进程异常终止,此时可通过WTERMSIG(status)
获取使得进程退出的信号编号。 waitpid(id,&status,0)
时,会一直等着子进程做完事情,什么事情也做不了。
WNOHANG
的方式://child
pid_t id = fork();
if(id == 0)
{
int count=5;
while(count)
{
printf("child: i am running %d, ppid: %d, pid: %d\n",count--,getppid(),getpid());
sleep(1);
}
printf("child: i quit....\n");
exit(10);
}
//father
int status =0;
pid_t ret = waitpid(-1,&status,WNOHANG);
while(1)
{
if(ret == 0)
{
printf("wait next !\n");
printf("fatehr do other thing\n");
}
else if(ret >0)
{
printf("wait sucess \n");
printf("exit code: %d,quit signal: %d, pid: %d\n",WEXITSTATUS(status),WIFEXITED(status),ret);
break;
}
else
{
printf("wait failed\n");
break;
}
}
#include `
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
...
execve
是真正的系统调用,其它五个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在man手册第3节。int main()
{
printf("my process begined.....\n");
execl("/user/bin/ls","ls","-a",NULL)//要以空 结尾
}
int execlp(const char *file, const char *arg, ...);
#include
#include
#include
#include
#include
int main()
{
pid_t rid=fork();
if(rid==0)
{
int cou=5;
while(cou--)
{
printf("child: %d, ppid: %d,read to run other,%d\n",getpid(),getppid(),cou);
sleep(1);
}
execlp("top","top",NULL);
exit(11);
}
int status =0;
pid_t ret = waitpid(-1,&status,0);
if(ret >0 && WIFEXITED(status)== 0)//信号
{
printf("wait sucess !\n");
printf("exit code: %d,quit signal: %d, pid: %d\n",WEXITSTATUS(status),WIFEXITED(status),ret);
}
else{
printf("wait failed quit signal: %d\n", WIFEXITED(status));
}
return 0;
}
int execle(const char *path, const char *arg, ...,char *const envp[]);
#include
#include
#include
#include
#include
int main(int argc,char* argv[],char* env[])
{
pid_t rid=fork();
if(rid==0)
{
int cou=5;
while(cou--)
{
printf("child: %d, ppid: %d,read to run other,%d\n",getpid(),getppid(),cou);
sleep(1);
}
execle("/usr/bin/ls","ls","-i",NULL,env);
exit(11);
}
.....
}
int execve(const char *path, char *const argv[], char *const envp[]);
//T1.C
#include
#include
int main()
{
int i=0;
for(;i<2;++i)
{
printf("i am here hh, test for execve(); use getenv(...)\n");
}
printf("environment variable: %s\n",getenv("MY_ENV"));
return 0;
}
---------------------
int main()
{
pid_t rid=fork();
if(rid==0)
{
int cou=5;
while(cou--)
{
printf("child: %d, ppid: %d,read to run other,%d\n",getpid(),getppid(),cou);
sleep(1);
}
char* const my_argv[]={
"t1",
NULL
};
char* const my_env[]={
"MY_ENV= hello execve!",
NULL
};
execve("./t1",my_argv,my_env);
exit(11);
}
....
}
int execvpe(const char *file, char *const argv[], char *const envp[]);
[saul@VM-12-7-centos tt729]$ export my_env="hello execvpe hh cannot add gantanhao" ...自定义的环境变量
[saul@VM-12-7-centos tt729]$ PATH=$PATH:/home/saul/tt729 ..运行程序不用加 。/
[saul@VM-12-7-centos tt729]$ vim t1.c
//t1。c
#include
#include
int main()
{
int i=0;
for(;i<2;++i)
{
printf("i am here hh, test for execvpe(); use getenv(...)\n");
}
printf("environment variable: %s\n",getenv("my_env"));
return 0;
}
//main
int main(int argc,char* argv[],char* env[])
{
pid_t rid=fork();
if(rid==0)
{
int cou=5;
while(cou--)
{
printf("child: %d, ppid: %d,read to run other,%d\n",getpid(),getppid(),cou);
sleep(1);
}
char* const my_argv[]={
"t1",
NULL
};
execvpe("t1",my_argv,env);
exit(11);
}
}
int execvp(const char *file, char *const argv[]);
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
// 带p的,可以使用环境变量PATH,无需写全路径
execvp("ps", argv);
}
v
:exec参数列表:传的是:该程序命令行参数列表的字符指针数组,p
:自动获取全局变量PATH;exec参数列表:前面的第一个参数可以不加路径;l
:在exec 参数列表一个个传过去 程序的使用方法。l , v 都以 NULL
结尾。e
:在exec 参数列表:
exec*
函数的方式可以在一个语言程序内,跑另外一个语言的程序。int execv(const char *path, char *const argv[]);
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
execv("/user/bin/ps", argv);
}