Linux环境变量编程--进程创建

1.进程号获取

pid_t getpid(void); 返回当前进程的进程号
pid_t getppid(void); 返回当前的进程的父进程

2.fork()函数创建子进程

fork:目的是在当前进程下创建一个子进程.

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次.  它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程.在子进程中fork函数返回0,在父进程中,fork返回新创建子进程的进程ID大于0。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

0 表示的是子进程的进程号,那么这个fork是父进程执行的结果
0 表示的是,这是由子进程执行的结果
-1 父进程创建子进程失败,此时不会有子进程创建

2.1 父进程和子进程执行顺序?是否会阻塞?

执行的顺序是随机的,不会阻塞

2.2 进程数据共享么?

父进程再调用fork之后,会把父进程的进程空间(fork之前的东西变量什么的)拷贝到子进程中,但fork之后父子进程创建的变量,如下面代码中的变量d,地址就不会是一样的.由于这种拷贝是完全拷贝,所以父子进程之间是不共享的。意思就是,虽然地址一样,但是各自修改,都不会影响另一方,大家地址空间独立的,即便地址一样又能怎样.

fork之前的变量,加不加static,无所谓,只是换了个进程空间的data段区域,还是会拷贝.

附注:查阅资料,后来的操作系统优化,通过写时复制技术,在子进程需要复制资源(比如子进程执行写入动作更改父进程内存空间)时才复制,否则创建子进程时先不复制。

2.3 子进程何时执行?

子进程是在调用fork函数之后才存在的,在fork之前的语句只有父进程执行,父进程fork之后,产生子进程,fork父子进程同时执行。

2.4 子进程{}之后的代码是谁的?

之后的代码是父子进程都会执行的。
fork之后筛选之前的语句,也是父子进程共同拥有的.

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

int c = 3;
int main(int argc, char const *argv[])
{
	int a = 1;
	static int b = 2;
	printf("before fork:a = %d\n", a); 
  	printf("**********************************\n");

	pid_t pid = fork(); //创建了一个子进程
	int d = 5;
	printf("pid号=%d\n",pid);  //运行结果会是两个:  //我pid=4392   //我pid=0												
	printf("fork_pid = %d, pid=%d, ppid=%d,hello world\n", pid, getpid(), getppid());
	printf("**********************************\n");
	//根据fork的返回值,进行父子进程筛选
	if(pid < 0) {
		perror("fork");
		return -1;
	} else if(pid > 0) { //父进程
		sleep(5);
		a = 11;
		//static int d = 40;
		printf("父进程:pid = %d, ppid = %d\n", getpid(), getppid());
		printf("父进程:a = %d, b = %d, c = %d \n", a, b, c);
		printf("d = %d,地址=%p\n", d,&d);
		printf("a 地址 %p\n",&a );//fork之后,abc变量本身的地址都是一样的.

	}else if(0 == pid) { //子进程
		//sleep(1);
		a = 10;
		b = 20;
		c = 30;
		d = 50;


		int d = 43;
		//static int d = 400;
		printf("子进程:pid = %d, ppid = %d\n", getpid(), getppid());
		printf("子进程:a = %d, b = %d, c = %d\n", a, b, c);
		printf("d = %d,地址=%p\n", d,&d);
		printf("a 地址 %p\n",&a );fork之后,abc变量本身的地址都是一样的.
	}


	printf("hello world pid = %d\n", getpid());
	printf("\n");
	return 0;
}

执行结果:
在这里插入图片描述

3. vfork()函数创建子进程

vfork函数并不会向fork那样把父进程的地址空间拷贝到子进程

3.1 父子进程执行顺序?

vfork产生子进程,子进程就在父进程的地址空间运行,所以子进程会阻塞父进程.看清这个所以的关系,因为子进程在父进程地址空间上运行,所以肯定会阻塞父进程.为什么就所以的那么理所应当,因为如果同时在同一块地方上撒欢,那不就乱套了吗,这就是所谓的并发.

3.2 父子进程何时执行?

子进程运行在vfork之后.
exit之后父进程才可能被调度运行。

附注:查阅资料,在fork中子进程与父进程的执行顺序不确定,而在vfork中,子进程先运行,父进程挂起,直到子进程调用了exec或者exit函数,父进程才被执行。

3.3 子进程{}之后的代码是谁的?

如果子进程在{}已经退出,之后的代码就属于父进程的.

3.4 进程数据共享么?

由于子进程是在父进程的地址空间运行,那么数据会共享.但是对于非静态(自动)的局部变量,在vfork之前可以共享,在vfork之后不能共享(因为子进程结束后,会释放栈区空间,即便在子进程修改了vfork之后的自动变量,子进程结束时也会清掉,父进程执行时候,又重新压一遍vfork之后的自动变量).子进程和父进程共享数据段,全局变量和静态的局部变量是完全共享的,静态局部变量在编译的时候就已经存在了(这里要记住static作用有三,修饰函数,全局变量,局部变量).

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

int main(int argc, char const *argv[])
{
	int a = 1;
	pid_t pid = vfork();

	int b = 5;//data
	static int c = 6;
	if(pid < 0) {
		perror("vfork error");
		exit(-1);
	}else if(0 == pid) { //子进程
		sleep(1);
		a = 10;
		b = 50;
		c = 80; 	///int b = 20;		
		printf("子进程:a = %d  b = %d  c = %d\n", a,b,c);
		exit(0);    //千万不要忘,fork也要养成该习惯
	}else if(pid > 0) { //父进程
		printf("父进程:a = %d  b = %d  c = %d\n", a,b,c);//父进程不能访问b,作用域														
	}
	printf("hello world pid = %d\n", getpid());
	return 0;
}

运行结果:
子进程:a = 10 b = 50 c = 80
父进程:a = 10 b = 5 c = 80
hello world pid = 7358

如果在vfork中,子进程没有exit()退出,就会显示以下结果的错误:

  • 子进程有exit时的运行结果:
    子进程:a = 10 c = 50 d = 80
    父进程:a = 10 c = 5 d = 80
    hello world pid = 3899

  • 无exit时的运行结果:
    子进程:a = 10 c = 50 d = 80
    hello world pid = 3908
    父进程:a = 32765 c = 5 d = 80
    hello world pid = 3907

a.out: cxa_atexit.c💯 __new_exitfn: Assertion `l != ((void *)0)’ failed.
已放弃 (核心已转储)

一定要谨记住:  vfork子进程退出一定要exit!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值