进程

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;
}

你可能感兴趣的:(Linux应用开发,进程,fork,exit,waitpid,exec)