linux多任务编程

1.fork()函数

fork()函数用于从已经从在的进程中创建一个新进程。新进程为子进程,原进程为父进程。在父进程中执行fork()函数时,父进程会复制出一个子进程,而且父子进程的代码从fork()函数的返回开始分别在两个地址空间中同时运行,从而使两个进程分别获得其所属fork()函数的返回值,其中在父进程中的返回值是子进程的进程号,而在子进程中返回0。因此,可以通过返回值来判断是父进程还是子进程。

使用fork()函数的代价是很大的,它复制了父进程中的代码段、数据段和堆栈段里的大部分内容,使用fork()函数的系统开销比较大,执行速度也不是很快。

代码如下

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(void)
{
	pid_t result;
	//调用fork函数
	result = fork();
	if(result == -1)//错误
	{
		printf("Fork error\n");
	}
	else if(result == 0)//返回值0代表子进程
	{
		printf("The returned value is %d\n\
		In child process!\n My PID is %d\n",result,getpid());
	}
	else //返回值大于0 代表父进程
	{
		printf("The returned value is %d\n\
		In father process!\n My PID is %d\n",result,getpid());
	}
	return result;
}

执行结果如下

book@100ask:~/linux_multi_fork$ ./01_fork
The returned value is 3086
                In father process!
 My PID is 3085
The returned value is 0
                In child process!
 My PID is 3086

由于fork()完整地复制了父进程的整个地址空间,执行速度比较满。为了加快fork()的执行速度,unix系统设计者创建了vfork().

vfork()也能创建新进程,但它不产生父进程的副本。它是通过允许父子进程可访问相同物理内存,从而伪装了对进程地址空间的真实复制,当子进程需要改变内存中的数据时才复制父进程。这就是写操作时复制技术。

2.exec函数族

fork()函数用于创建一个子进程,该子进程几乎复制了父进程的全部内容;exec函数族提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段、堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。这里的可执行程序可以是二进制文件或任何可执行的脚本文件。

在linux中使用exec函数族主要有两种情况:

1>当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。

2>如果一个进程想执行另一个程序,就调用fork()函数新建一个进程然后调用exec函数族中的任意一个函数,这样看起来 就像通过执行应用程序而产生一个新进程。

2.1execlp()函数

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	pid_t result;
	//调用fork函数
	result = fork();
	if(result == -1)//错误
	{
		printf("Fork error\n");
	}
	else if(result == 0)//返回值0代表子进程
	{
		//调用execlp函数,这里相当于调用了“ps -ef”命令
		if(execlp("ps","ps","-ef",NULL) < 0)
		{
			printf("Execlp error\n");
		}
	}
	
	return result;
}

执行结果如下:

2.2 execl()函数

此函数必须要用以“/”开头的完整的文件目录查找对应的可执行文件。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	pid_t result;
	//调用fork函数
	result = fork();
	if(result == -1)//错误
	{
		printf("Fork error\n");
	}
	else if(result == 0)//返回值0代表子进程
	{
		//调用execl函数,这里相当于调用了“ps -ef”命令,但要给出完整的路径
		if(execl("/bin/ps","ps","-ef",NULL) < 0)
		{
			printf("Execlp error\n");
		}
	}
	
	return result;
}

执行结果

2.3 execle()函数

将环境变量添加到新建的子进程中,这里的“env”是查看当前环境变量的命令

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	pid_t result;
	char *envp[]={"PATH=/tmp","USER=david",NULL};
	//调用fork函数
	result = fork();
	if(result == -1)//错误
	{
		printf("Fork error\n");
	}
	else if(result == 0)//返回值0代表子进程
	{
		if(execle("/usr/bin/env","env",NULL,envp) < 0)
		{
			printf("Execle error\n");
		}
	}
	
	return result;
}

执行结果

 

2.4 execve()函数

通过构造指针数组的方式来传递参数,注意参数链表一定要以NULL作为结束符。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	pid_t result;
	char *arg[] = {"env",NULL};
	char *envp[]={"PATH=/tmp","USER=david",NULL};
	//调用fork函数
	result = fork();
	if(result == -1)//错误
	{
		printf("Fork error\n");
	}
	else if(result == 0)//返回值0代表子进程
	{
		if(execve("/usr/bin/env",arg,envp) < 0)
		{
			printf("Execve error\n");
		}
	}
	
	return result;
}

 执行结果

3. exit()和_exit()

1>exit()和_exit()函数都是用来终止进程的。当程序执行到exit()和_exit()时,进程会无条件停止剩下的所欲操作,清除各种数据结构,并终止本进程的运行。

区别:

exit()在终止当前基础之前要检查该进程打开国那些文件,把文件缓冲区中的内容写回文件;

_exit()直接使进程停止运行,清除其使用的内存空间,并清除其字内核中的各种数据结构。

exit()代码


#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	printf("Using exit ...\n");
	printf("This is the content in buffer");
	exit(0);
}

执行结果

 _exit()代码

#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	printf("Using exit ...\n");
	printf("This is the content in buffer");
	_exit(0);
}

执行结果

去掉第二个printf最后的回车符,代码如下

#include <stdio.h>
#include <stdlib.h>


int main(void)
{
	printf("Using exit ...\n");
	printf("This is the content in buffer\n");
	_exit(0);
}

执行结果

4.wait()和waitpid()

wait()函数用于使父进程阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()就会立即返回。

waitpid()的作用和wait()一样,但它并不一定要等待第一个终止的子进程,它有若干选项,可以提供一个非阻塞版的wait()功能,也能支持作业控制。

代码

//waitpid
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
	pid_t pc,pr;
	
	pc = fork();
	if(pc < 0)
	{
		printf("Error fork\n");
	}
	else if(pc == 0)//子进程
	{
		sleep(5);
		exit(0);
	}
	else//父进程
	{
		//循环测试子进程是否推出
		do
		{
			//调用waitpid(),且父进程不阻塞
			pr = waitpid(pc, NULL, WNOHANG);
			
			//若子进程还未退出,则父进程暂停1s
			if(pr == 0)
			{
				printf("The child process has not exited\n");
				sleep(1);
			}
		}while(pr == 0);
		
		//若发现子进程退出,打印出相应情况
		if(pr == pc)
		{
			printf("Get child exit code: %d\n",pr);
		}
		else 
		{
			printf("Some error occured.\n");
		}
	}
}

执行结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值