进程控制
1.进程创建
给父进程创建一个子进程,父子进程代码数据独立代码共享。
函数:fork() 返回值是 int
1.父子进程代码共享
fork()函数有两个返回值,调用函数创建进程的大体过程是这样的。
父进程接收到返回值是子进程的pid,子进程接收到的返回值是0。
int main()
{
pid_t id = fork(); //该语句执行后子进程已经被创建
//之后的代码父子共享.
printf("hello world\n");
return 0;
}
fork()之后的代码父子共享,各执行一次。
2.父子进程数据独立
从大体上可以认为数据就是独立,但事实上对于父子进程没有修改的数据,他们仍然是共享的。对于某个数据父子进程对它进行写入,这时通过写时拷贝技术来让它们这些数据独立。
2.进程终止
进程终止的几种情况
1.程序运行完,结果正确。
2.程序运行完,结果不正确。
3.程序没有运行完(程序崩溃)。
1.终止方式
1.主函数return
2.exit(退出码)退出整个进程
3._exit
2.return
return 只有在主函数使用才会让程序终止,它仅仅只是函数的返回值。
int main()
{
printf("before return\n");
return 1;
printf("after return\n");
return 0;
}
return 1;之后直接进程结束。之后的语句不再被执行。
3._exit
_exit是系统调用函数,由操作系统直接终止函数。
在程序任意位置调用均可终止。
void Myexit()
{
_exit(0);
}
int main()
{
Myexit();
printf("after exit\n");
return 0;
}
4.exit()
在程序任意位置调用exit()函数
exit()函数内部是通过调用_exit()函数终止进程,与_exit不同的是,exit()在调用_exit()之前,会刷新缓冲区。
3.进程等待
1.进程等待概念
父进程创建子进程执行任务,父进程可以通过调用进程等待函数,等待子进程执行完毕,获取子进程的退出信息。
2.进程等待意义
父进程调用子进程执行任务,若父子进程同时执行不同的任务,那么子进程在执行完毕后,退出信息无法被回收,变成僵尸进程,造成内存泄漏。
若父进程调用进程等待函数等待子进程执行终止后获得退出信息,回收内存,可以避免内存泄漏。
3.进程等待函数
1.wait()
pid_t wait(int *status);
函数执行成功返回值是子进程的pid,失败返回 -1.
status是输出型参数,用于带回子进程退出信息。
对于status而言只有低16位用于存储返回信息。高16位无意义。
1.若正常退出,低16中的低 8 位存0表示正常退出,高8位存储退出码。
假设用st接收,status带回的退出信息。则正常退出的退出码就是 (st >> 8) & 0x0f
int main()
{
pid_t id = fork();
if(id < 0)
{
cout << "fork error!" << endl;
exit(0);
}
else if(id == 0)
{
// child
int second = 0;
while(second++ <= 5)
{
printf("this is child\n");
sleep(1);
}
exit(1); // 1 是子进程的退出码
}
else if(id > 0)
{
//parent
int st;
pid_t childId = wait(&st);
//打印wait 的返回值和子进程的退出码
printf("this is parent process, child id is %d , exit code is %d\n", childId, (st >> 8) & 0x0f);
}
return 0;
}
2.waitpid
pid_t waitpid(pid_t pid, int *status, int options)
waitpid是等待某一个具体进程。
返回值:成功返回进程pid,失败返回-1,如果设置了WNOHANG表示以非阻塞方式等待,若当前没有退出的进程返回0.
参数:
pid : pid = -1,等待任意子进程,与wait等效
pid > 0, 等待进程该pid的进程。
status:
1.WIFEXITED(status): 进程正常退出为真,否则为假.相当于 !(st & 0x7f)
2.WEXITSTATUS(status):正常退出返回进程退出码。 st >> 8 & 0x0f