进程控制

进程的生命周期:

创建:每个进程都由其父进程创建。父进程可以创建子进程,子进程又可以创建子进程的子进程。

运行:多个进程可以同时存在,进程之间可以进行通信。

终止:结束一个进程的运行。

获取id的函数  pid_t getpid

pid_t getpid(void)  获取当前进程的id

pid_t getppid(void)获取父进程的id


进程创建函数fork()

当fork()顺利完成任务时,就会存在两个进程,每个进程都从fork()返回处开始继续执行。

两个进程执行相同的代码(text)段,但是有各自的堆栈(stack)段、数据(data)段以及堆(heap)。

子进程的stack、data、heap segments是从父进程拷贝过来的。

fork()之后,哪一个进程先执行(scheduled to use the CPU)不确定。

#include <stdio.h>
#include <unisted.h>
#include <sys/types.h>

int main()
{
	pid_t pid = fork();
	
	if (pid < 0)
	{
		printf("error in fork\n");
	}
	else if (pid == 0)
	{
		printf("I am the child process, ID is %d\n",getpid());
	}
	else
	{
		printf("I am the parent process, ID is %d\n",getpid());
	}
	
	return 0;
}
fork的返回值为-1的时候说明创建子函数失败,为0的时候说明当前进程是子进程,大于0的说明是父进程。


execl函数创建一个新的程序代替当前的进程,其pid不会改变。

#include <stdio.h>
#include <unistd.h>
 
int main()
{
    execl ("/bin/ls", "ls", "-al", "/home", NULL);
  
    int a[10] = {2,3,1,6,5,4,8,7,0,9};
	int i;
	for(i=0; i<10; i++)
	{
		int j;
		for(j = 0; j<9-i; j++)
		{
			if(a[j]>a[j+1])
			{
				int tmp = a[j];
				a[j] = a[j+1];
				a[j+1] = tmp;
			}
		}
	}
	
	for(i=0;i<10;i++)
	{
		printf("%4d",a[i]);
	}
	printf("\n");

  return 0;
}
该程序最后的运行结果是终端上的列表当前目录下的文件  就是ls -l 的功能,execl函数下的所以代码都没有被实现。
与此差不多功能的还有execlp和execv两个函数,只不过execlph函数需要的是文件在path下的路径里。execv函数将后面的参数放入了一个数组,其本质上效果是一样的。

system函数是调用fork产生子进程,由子进程来调用 /bin/sh -c string来执行参数string所代表的命令。


exit函数:用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。

_exit函数则是终结当前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据不会写回并关闭未关闭的文件。


僵尸进程的产生:僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸。

 父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。

子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。

在 wait 调用之后,僵尸进程就完全从内存中移除。


若父进程比子进程先终止,则该父进程的所有子进程的父进程都改变为init进程。我们称这些进程由init进程领养。其执行顺序大致如下:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止的进程的子进程,如果是,则该进程的父进程ID就更改为1(init进程的ID)。


由于父函数的先结束,子函数将继续在后台运行下去,所以这种状况又产生了一种守护进程:

int daemonize(int nochdir, int noclose)
{
	pid_t pid = fork();
	if (pid > 0)
	{
		exit(0);
	}
	else if (pid < 0)
	{
		return -1;
	}
	
	umask(0);
	
	if (setsid() < 0)
	{
		return -1;
	}
	
	if (nochdir == 0 )
	{
		// 4、改变当前的工作目录
		if (chdir("/") < 0)
		{
			return -1;
	}
	}
	
	close(STDIN_FILENO);
	close(STDOUT_FILENO);
	close(STDERR_FILENO);
	
	if (noclose == 0)
	{
		open("/dev/null", O_RDONLY);   // 0 
		open("/dev/null", O_RDWR);   // 1
		open("/dev/null", O_RDWR);   // 2
	}

	return 0;
}

int main()
{
	// daemonize(0,0);
	daemon(0,0);
	while (1);
	

	return 0;
}


wait函数在函数中如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。如果它没有任何子进程,则立即出错返回。
在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。 waitpid并不等待在其调用之后的第一个终止的子进程。它有若干个选项,可以控制它所等待的进程。

 WIFEXITED(status)若子进程正常终止,该宏返回true。此时,可以通过WEXITSTATUS(status)获取子进程的退出状态(exit status)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值