1、 什么是进程
进程是一个执行的过程
进程是一段独立的程序,在某个数据集合上的一次运行的过程
./a.out(回车)产生了一个进程
2、进程和程序的区别和联系
什么是程序----程序是写好的代码,是一个文件,可以保存
进程是不能保存的,程序是可以保存的
进程是动态的,程序是静态的
程序经过编译运行产生进程
进程是操作系统分配资源的最小单位
了解
init----PID == 1
操作系统第一个进程 始祖
进程类型:
交互进程
批处理进程
守护进程
理解进程状态
运行态 就绪态 等待态
3、理解fork
fork用来创建进程
在程序中使用fork成功后,会有父进程和子进程
可以通过fork的返回值来区分父子进程
我们不确定CPU先调度哪一个
getpid()的返回值是调用它的进程的进程号
getppid()的返回值是调用它的进程B的父进程A的进程号
结论:fork在创建子进程成功时,给父进程返回的值,是创建好的那个子进程的PID
fork给子进程返回的值是0
fork.c
#include
#include
#include
//创建进程,父子进程执行相同的打印语句
int main()
{
pid_t pid = -1;
pid = fork();//create process
if (pid < 0)
{
perror("fork error");
return -1;
}
if (0 == pid)
{
sleep(10);
printf("child process, %d\r\n", getpid());
printf("%d\r\n", getppid());
}
else
{
printf("parent process, %d\r\n", pid);
printf("%d\r\n", getpid());
}
printf("after fork\r\n");
return 0;
}
4、进程的退出
1、程序运行结束 --------main中的return
2、收到信号(中断)
3、程序中调用进程退出的函数exit,_exit
exit在进程退出时,回收资源
僵尸进程——自己写代码时,需要避免出现僵尸进程,父进程使用wait/waitpid可以避免产生僵尸进程
孤儿进程——父进程先结束,子进程被称为是孤儿进程。孤儿进程会由init进程收养
#include
#include //exit
#include //_exit
//exit,_exit是进程退出函数
int main()
{
int i = 3;
while (i--)
{
if (1 == i)
{
_exit(0);
}
}
printf("break from while\r\n");
return 0;
}
5、等待子进程结束
wait
waitpid
子进程在退出时调用了 exit(10)
父进程回收资源,想要获得子进程退出状态 wait()
pid_t wait(int * status); // 调用它时,需要传参
pid_t waitpid(pid_t pid, int * status, int options); //一般用的比较多的是:waitpid ( pid, &status, WNOHANG);----非阻塞
得到的子进程退出状态存放在status中,用下面的两个宏来取出退出原因和状态
if ( WIFEXITED ( status ) )
{
printf("%d exit normall,status = %d\r\n", ret, WEXTSTATUS(status));
}
#include
#include
#include
#include
#include
//创建进程,父子进程执行相同的打印语句
int main()
{
pid_t pid = -1;
pid = fork();//create process
if (pid < 0)
{
perror("fork error");
return -1;
}
if (0 == pid)
{
sleep(10);
printf("child process, %d\r\n", getpid());
exit(10);
}
else
{
int status = 0;
int ret = 0;
do {
ret = waitpid(pid, &status, WNOHANG);
printf("%d\r\n", getpid());
printf("parent process, %d\r\n", pid);
sleep(1);
}while(0 == ret);
if (WIFEXITED(status))
{
printf("%d exit normall, status = %d\r\n", ret, WEXITSTATUS(status));
}
}
printf("after fork\r\n");
return 0;
}
6、exec
exec函数族提供了一种在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段、和堆栈段。在执行完之后,原调用进程的内容除了进程号外,其他全部都被替换了。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
何时使用?
当进程认为自己不能再为系统和用户做任何贡献了就可以调用exec函数族中的函数,让自己执行新的程序。
当前目录: 可执行程序A B(1,2,3)
如果某个进程想同时执行另一个程序,它就可以调用fork函数创建子进程,然后在子进程中调用任何一个exec函数。这样看起来就好像通过执行应用程序而产生了一个新进程一样。
exec函数族使用注意点
在使用exec函数族时,一定要加上错误判断语句。
因为exec很容易执行失败,其中最常见的原因有:
①找不到文件或路径,此时errno被设置为ENOENT。
②数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT。
③没有对应可执行文件的运行权限,此时errno被设置为EACCES。
#include
int main()
{
//execlp("ls", "ls", "-l", "/home/farsight", NULL);
//execl("/bin/cat", "cat","wait2.c", NULL);
char * argv[] = {"ls", "-l", "/mnt/hgfs", NULL};
//execv("/bin/ls", argv);
//execvp("ls", argv);
char * envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
//execle("/bin/ls", "ls", "/mnt/hgfs", NULL, envp);
//execve("/bin/ls", argv, envp);
char * cmd[] = {"hello" , NULL};
execve("./hello", cmd, NULL);
return 0;
}