Linux学习_系统进程的创建

进程的创建

一些基础知识:
什么是文件描述符表?参照stdin,stdout,stderr
什么是文件表项?包含文件状态标志、当前偏移量,i-node指针,引用计数器
什么是i节点? 包含文件长度、文件所有者、指向磁盘块的指针。
什么是进程表项?

1.进程的创建函数

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

pid_t fork(void);
返回:子进程中返回0, 父进程中返回子进程ID,出错返回-1

pid_t vfork(void);
返回:子进程中返回0, 父进程中返回子进程ID,出错返回-1
  • fork创建的新进程被称为子进程,该函数被调用一次,但返回两次。两次返回的区别是:在子进程中的返回值是0,而在父进程中的返回值则是新子进程的进程ID。
  • fork创建子进程,父子进程哪个先运行根据系统调度,且复制父进程的内存空间
  • vfork创建子进程,但子进程先运行且不复制父进程的内存空间
    注意:
main()
{
	...
	fork();
	fork();
	fork();
	...
}
这里会产生 2^3个子进程, 一般不会用这种方式创建

案例1:父进程和子进程

/*
 * 创建进程.c
 * 
 */

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

int main(int argc, char **argv)
{
	printf("pid:%d\n",getpid());
	pid_t pid;
	pid=fork(); //创建子进程
	//在fork之后会运行两个进程(父进程和子进程)
	if(pid<0){
		perror("fork error");
	}
	else if(pid>0){ 
		//在父进程中fork返回的是子进程的ID
		//这里写父进程执行代码
		printf("I am parent process, pid is %d,ppid is %d, fork return is %d\n",\
					getpid(),getppid(),pid);
	}else{ 
		//子进程(在子进程中fork返回0)
		//这里写子进程执行代码
		printf("I am child process, pid is %d,ppid is %d, fork return is %d\n",\
					getpid(),getppid(),pid);
	}
	printf("pid: %d\n",getpid());
	sleep(1);
	
	exit(0);
}

案例2:进程的调度

  • 父进程和子进程交替运行
  • 父进程sleep时运行子进程,子进程sleep时运行父进程
  • 使用fork(),父子交替运行
  • 使用vfork(),子进程运行完毕,再运行父进程
/*
 * 进程调度.c
 * 
 */

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

int main(int argc, char **argv)
{
	printf("current pid:%d\n",getpid());
	pid_t pid = fork(); //创建子进程
	//pid_t pid = vfork(); //先运行子进程(直到运行完毕)再运行父进程
	
	//在fork之后会运行两个进程(父进程和子进程)
	if(pid<0){
		perror("fork error");
	}
	else if(pid>0){ 
		//在父进程中fork返回的是子进程的ID
		//这里写父进程执行代码
		for(int i=0;i<5;++i){
			printf("I am parent process, pid is %d\n",getpid());
						sleep(1);
			}
	}
	else{ 
		//子进程(在子进程中fork返回0)
		//这里写子进程执行代码
		for(int i=0;i<5;++i){
			printf("I am child process, pid is %d\n",getpid());
						sleep(1);
			}
	}
	
	exit(0);
}

输出:

fork()输出:
current pid:7282
I am parent process, pid is 7282
I am child process, pid is 7283
I am parent process, pid is 7282
I am child process, pid is 7283
I am parent process, pid is 7282
I am child process, pid is 7283
I am parent process, pid is 7282
I am child process, pid is 7283
I am parent process, pid is 7282
I am child process, pid is 7283


vfork()输出:
current pid:7316
I am child process, pid is 7317
I am child process, pid is 7317
I am child process, pid is 7317
I am child process, pid is 7317
I am child process, pid is 7317
I am parent process, pid is 7316
I am parent process, pid is 7316
I am parent process, pid is 7316
I am parent process, pid is 7316
I am parent process, pid is 7316

2.继承的概念

  • 子进程的继承属性
    • 用户信息和权限、目录信息、信号信息、环境、共享存储段、资源限制、堆、栈和数据段,共享代码段。,虚拟地址和父进程一样
      正文段物理内存共享,其他都独立物理内存
  • 子进程特有属性
    • 进程ID、锁信息、运行时间、未决信号
  • 操作文件时的内核结构变化
    • 子进程只继承父进程的文件描述表,不继承但共享文件表项和i-node
    • 父进程创建一个子进程后,文件表项中的引用计数器加1变成2,当父进程作close操作后,计数器减1,子进程还是可以使用文件表项,只有当计数器为0时才会释放文件表项

案例3:fprint和write的缓存操作区别

/*
 * 子进程继承.c
 * fprint和write的缓存操作区别
 */

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

int global_v = 30;

int main(int argc, char **argv)
{
	int auto_v = 30;
	static int static_v = 30;
	printf("pid:%d\n",getpid());
	//标准IO调用
	FILE* fp = fopen("s.txt","w");
	
	//IO系统调用,不带缓存功能,直接操作
	int fd = open("s_fd.txt",
			O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU|S_IRWXG);
			//O_WRONLY: write only
			//S_IRWXU:00700 user (file owner) has read,  write,  and  execute permission
			// S_IRWXG  00070 group has read, write, and execute permission
			
	char *s = "hello world";
	ssize_t size = strlen(s)*sizeof(char);
	
	/*父进程调用*/
	//标准IO函数(带缓存-->全缓存)
	fprintf(fp,"s: %s, pid: %d\n", s, getpid()); //写入缓存
	
	//内核提供的IO系统调用(不带缓存)
	write(fd, s, size); //直接写入文件
	
	
	pid_t pid;
	pid=fork(); //创建子进程
	//在fork之后会运行两个进程(父进程和子进程)
	if(pid<0){
		perror("fork error");
	}
	else if(pid>0){ 
		//在父进程中fork返回的是子进程的ID
		//这里写父进程执行代码
		global_v=40, auto_v=40, static_v=40;
		printf("I am parent process, pid is %d,ppid is %d, fork return is %d\n",getpid(),getppid(),pid);
		printf("g_v: %p, a_v: %p, s_v: %p\n",&global_v, &auto_v, &static_v);
	}else{ 
		//子进程(在子进程中fork返回0)
		//这里写子进程执行代码
		global_v=50, auto_v=50, static_v=50;
		printf("I am child process, pid is %d,ppid is %d, fork return is %d\n",getpid(),getppid(),pid);
		printf("g_v: %p, a_v: %p, s_v: %p\n",&global_v, &auto_v, &static_v);
	}
	
	//父子进程都要执行(写入缓存)
	fprintf(fp, "pid: %d, g_v: %d, a_v: %d, s_v: %d\n",getpid(),global_v, auto_v, static_v);
	
	sleep(1);
	
	fclose(fp);
	close(fd);
	
	exit(0);
}

输出:

pid:8859
I am parent process, pid is 8859,ppid is 8849, fork return is 8860
g_v: 0x21054, a_v: 0xbee9f750, s_v: 0x21058
I am child process, pid is 8860,ppid is 8859, fork return is 0
g_v: 0x21054, a_v: 0xbee9f750, s_v: 0x21058
-------------------------------------------------------------
s.txt:

s: hello world, pid: 8859
pid: 8859, g_v: 40, a_v: 40, s_v: 40
s: hello world, pid: 8859
pid: 8860, g_v: 50, a_v: 50, s_v: 50
--------------------------------------------------------------
s_fd.txt:

hello world

案例4:父进程调节文件偏移量,子进程追加写入

/*
 * process_append.c
 * 父进程调节文件偏移量,子进程追加写入
 */


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

int main(int argc, char **argv)
{
	if(argc < 2){
		fprintf(stderr,"usage: %s file\n", argv[0]);
		exit(1); //exit(int status); status -- 返回给父进程的状态值。
		}
	int fd = open(argv[1], O_WRONLY); 
	//fd=file descriptor文件描述符
	if(fd<2){
		perror("open error");
		exit(1);
	}
	
	pid_t pid = fork(); //创建子进程
	if(pid>0){	//parent process
		//父进程将文件偏移量调整到文件尾部
		if(lseek(fd, 0L, SEEK_END) <0 ){ //off_t lseek(int fd, off_t offset, int whence);
			perror("lseek error");
			exit(1);
		}
	}
	else if(pid==0){	//child process
		//子进程从文件尾部追加内容
		char* str = "\nhello world";
		ssize_t size = strlen(str) * sizeof(char);
		sleep(3); //子进程睡眠3秒以上,保证父进程执行完毕
		
		//此处的fd是从父进程中复制过来的
		//但是和父进程中的fd都是指向同一个文件
		if(write(fd, str, size) != size){
			perror("write error");
			exit(1);
		}
	}
	else{
		perror("fork error");
		exit(1);
	}
	printf("pid: %d finish\n",getpid());
	sleep(1);
	
	//父子进程都要去关闭文件描述符
	close(fd);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值