Linux系统编程—进程
程序与进程
什么是程序?
程序是静态的概念,例如,
gcc xxx.c -o a
磁盘中生成的a文件就叫做程序1
什么是进程?
进程则是动态的概念,程序的运行起来,系统中就多了一个进程
如何查看系统中有哪些进程
1,使用ps指令查看,配合grep来查找
ps -aux|grp xxx
2,使用top指令查看,类似windows任务管理器
什么是进程标识符?
每个进程都有一个非负整数表示的唯一ID,pid
如何查看pid号
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid
pid = getpid();
printf("%d\n",pid);
return 0;
}
什么叫父进程,什么叫子进程
进程A创建了进程B,则称进程A为进程B的父进程,B叫做子进程
C程序的存储空间怎么分配
高地址:命令行参数和环境变量
低地址:栈
堆
未初始化的数据
初始化的数据
正文//代码段
进程创建
使用fork()创建进程
在man 2函数中查看原型
#include <unistd.h>
pid_t fork(void);
fork函数调用成功,返回两次
返回值为0, 代表当前进程是子进程
返回值是正数,代表当前进程为父进程
调用失败,返回-1
使用fork函数的目的:
(1):一个父进程希望通过复制自己,使父子进程同时执行不同的代码段。
(2):一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec
总结:fork调用一次返回两次,子进程返回0,父进程返回子进程的进程id,因为一个进程的子进程可以有多个,并且没有一个函数会使一个进程获得所以子进程的进程id。fork使子进程得到返回值为0,因为一个异常只会有一个父进程,所以子进程总是可以调用getpid()以获得其父进程的进程id(进程id 0总是由内核交换进程使用,所以一个子进程的进程id不可能为0)。子进程是父进程的副本,子进程获得父进程的数据空间,堆栈的副本,不共享存储空间部分,父子进程共享正文部分。
使用vfork()创建进程
同fork()创建进程区别:
一:vfork直接使用父进程存储空间,不拷贝。
二:vfork保证子进程先运行,当子进程调用exit退出之后,父进程才执行
进程退出
正常退出
1,main函数调用return
2,进程调用exit,标准c库
3,进程调用_exit或者_Exit(),属于系统调用
4,进程最后一个线程返回
5,最后一个线程调用pthread_exit
异常退出
1,调用abort
2,当进程收到某些信号时,如ctrl+c
3,最后一个线程对取消请求作出响应
不管进程如何终止,都会执行一段代码,为相应进程关闭所有打开描述符,释放他们所使用的存储器
父进程等待子进程退出,并收集子进程的退出状态
子进程退出状态不被收集,变成僵尸进程
wait()函数
函数原型为
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
wait()解析:
如果其所有子进程都还在运行,则阻塞
如果一个子进程已终止,正在等待父进程获取其终止状态,则取得该子进程的终止状态立即返回
如果它没有任何子进程,则立即出错返回
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int cnt = 0;
int status = 10;
pid = fork();
if(pid > 0)
{
wait(&status);
printf("child quit, child status = %d\n",WEXITSTATUS(status));
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print, pid = %d\n",getpid());
sleep(1);
}
}
else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 5){
exit(3);
}
}
}
return 0;
}
WEXITSTATUS(status):取子进程传送给exit, _exit, 或_Exit参数的低8位
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程1
Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程