纯新多进程学习基础

什么是进程?进程是如何被定义的

程序员第一弹:进程


学习目录

  • 什么是进程?进程是如何被定义的
  • 前言
  • 一、什么是进程?
    • 问:什么是进程ID?
    • 问:进程与程序有什么区别?
    • 问:进程与线程的区别?
    • 问:多线程相比多进程的优势
    • 问:进程有哪几种状态?
    • 问:如何理解进程的三种状态?
    • 问:什么是PCB【进程控制块】?
  • 二、使用需知
    • 1.进程标识
  • 三:进程管理
    • 1:进程启动
    • 2:fork()
    • 3:exec()
    • 4:system()
  • 四:进程终止
  • 五:进程间通信
    • 共享内存
    • 5:结语


前言

  网络水太深,你把握不住……Hello!大家好,这里是小新。今天我们来聊聊让新手程序员们一直以来都谈之色变的——进程


提示:以下内容为以LINUX操作系统为主

一、什么是进程?

所谓进程——是一个程序的一次执行过程,他有以下几种特性。
   1:他是一个独立的可调度对象
   2:他是一个抽象的实体,既当他执行某个任务时,将要分配和释放资源
   3:是可以并行执行的的计算部分。

问:什么是进程ID?

答:进程的唯一数字标识符被称之为进程ID,他是一个非负整数。
   在C语言中用pid_t类来表示、

问:进程与程序有什么区别?

答:
   1:进程是动态的,程序是静态的。
   2:进程是暂时的,程序是永久的。
   3:组成不同:进程组成包括程序,数据和进程控制模块。
   4:一个程序可以对应多个进程,一个进程也可以包括多个程序

问:进程与线程的区别?

答:
   1:线程是一个进程中的多个执行路线
   2:线程是一个进程内部的一个控制序列
   3:所有进程都至少有一个执行线程

问:多线程相比多进程的优势

答:
   1:多线程你可以想象成一种非常有效率的多任务操作方式。
   原理:一个进程的启动就必须给这个进程分配独立的地址空间,多线程则是使用原有的相同的地址空间,而且线程的切换时间远远小于进程。
   2:线程间通讯方便
   原理:线程共享数据空间,一个线程的数据可以直接为其他线程所用。

问:进程有哪几种状态?

答:有运行,挂起,停止,僵尸等状态,进程切换的时候需要保存和恢复一些cpu寄存器。

问:如何理解进程的三种状态?

答:
   1:就绪状态:进程已经获得除处理机外的所需资源,等待分配处理机资源;只要分配CPU就可执行。可以按照过个优先级来划分队列:时间片用完【优低】,IO完成[中优】,页面调入完成【高优】
   2:运行状态:占用处理机资源。处于此状态的进程树木小于等于CPU的树目。所有进程阻塞状态的情况会执行空操作【idle进程】
   3:阻塞状态:进程在等待某种条件,只有满足条件才有后续。
纯新多进程学习基础_第1张图片

问:什么是PCB【进程控制块】?

答:他是操作系统内核中的一种数据结构,主要用来表示进程的状态

二、使用需知

1.进程标识

   !:在Linux中最主要的进程标示有进程号(PID)和他的父进程号(PPID)。
   2:当系统为一个新进程分配ID达到系统最大值时,系统会重新使用最小且当前没有被使用的PID号

pid_t getpid(void)
pid_t getppid(void)
//获取进程或父进程的id,失败返回-1

三:进程管理

1:进程启动

1:进程启动:
   手工启动:前台启动,后台启动
   调度启动:system(),fork(),exec() ps,top,kill,cron

2:fork()

//pid_t fork(void);的使用
int mian()
{
	fork();
	printf("小新太帅了');
	return 0;
}
//会打印出两次小新太帅了,说明新进程复制了父进程的内存空间
//父进程返回子进程的id,紫禁城返回0
int mian(void)
{
	pid_t pid;
	if((pid=fork())==-1)return -1;
	else if(pid==0)
	{
		printf("子=%d",getpid());
	}
	else
	{
		printf("父=%d",getpid());
	}
	return 0;
}

   创建后的子进程将复制父进程的数据段,BSS段,代码段,堆空间和栈空间。但会共享文件描述符会。大家可以自己敲一敲代码,尝试一下。

3:exec()

作用:
   1:在一个进程中启动另一个程序执行,既用新程序取代原调用进程的内存空间。如果一个进程想要执行另一个程序,调用fork()创建新进程后调用exec。
   2:当进程认为自己不能再为系统和用户做出任何贡献的时,调用exec函数族让自己重生

#include 
#include 

int exec(const char *path,const char *arg,……,NULL);
int exec(const char *file,const char*arg,……,NULL);
int execle(const char *path,const char *arg,……,NULL,char *constenvp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);最后都要调用这个函数。
//char *arg[3]={"ls","a",NULL};
//失败时有返回值,成功时无返回值。

这里就不做详细的介绍了,大家使用的时候就百度一下函数的内容。

4:system()

原型:int system(const char *string);
   在库#include
   返回值-1出现错误,成功返回子进程的退出状态

四:进程终止

   1:一个进程终止会关闭所有的文件描述符,释放在用户空间分配的内存:
   2:但任然会保留它的PCB,内核在其中保存了一些信息。
   3:正常终止保存着退出状态,异常终止保存着导致进程终止的信号。
   4:如果一个进程已经终止,但是它的父进程尚未调用wait或waitpid对它进行清理,这时的进程状态称为僵尸进程。任何进程在刚终止时都是僵尸进程。
正常终止:从mian返回,调用exit , _exit
异常终止:调用abort();由一个信号终止

include <stdlib.h>
void exit(int status) ;//exit则先执行一些清除处理.然后进入内核
 //清除操作包括调用执行各终止处理程序,关闭所有标准I / O流

#include 
void _exit (int status) ; //_exit立即进入内核,不会关闭标准I/O流


5:wait 和waitpid
wait是waitpid的一种特殊用法,父进程调用这两个函数的时候可能会出现以下三种情况。
   一:如果子进程还在运行,会发生阻塞
   二:如果子进程终止,正在等待父进程读取终止信息,带子进程的终止信息立即返回。
   三:如果它没有任何子进程,出错后立即返回

#include 
#include 

pid_t wait(int *status);//退出状态可以通过*statue获取;一次只可以处理一次
pid_t waitpid(pid_t pid, int *status, int options);//options参数中指定WNOHAN可以使父进程不阻塞而立即返回0
//pid参数用来指定等待哪一个子进程。

//pid>0时,只等待进程ID等于pid的子进程,不管其他进程。
//pid=-1时等待任何一个子进程退出,没有限制
//pid=0时,等待同一个进程组中的任何子进程。
//pid<-1时,等待一个指定进程组中的任何子进程,这个id等于pid的绝对值

说到这里,不得不说一下进程组函数

int setpgid(pid_t pid,pid_t gpid)//pid=0设置当前进程
pid_t getpgrp()//获取当前进程的组id号
pid_t getpgid(pid_t pid)//获取指定进程组id号
//gpid=0,用当前进程id作为组的id
//成功返回0,失败返回-1

理解不了小可耐写程序试一试哦!

五:进程间通信

常见的进程间通信息有如下几个
1:管道通信
2:共享内存
3:消息队列
4:信号
5:套接字
这里着重讲一下共享内存。

共享内存

   内容:共享内存区域是被多个进程的一部分物理内存。如果多个进程都把该内存映射到自己的虚拟地址空间,则这些进程就都可以直接访问共享内存区域,从而可以通过该区域进行通信。他是进程间共享数据最快的一种方式。
实现:
   一:创建共享内存,使用shmget函数
   二:映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数。

int shmgt(Key_t Key,int Size,int shmglg);//IPC_CREAT IPC_EXCL 0666
//Key值用以下函数得到
#include 
#include 
Key_t ftok(char *fname,int id)

//shmat
void *shmat(int shmid,char *shmaddr,int shmflg);//具体参数表小可耐可以查下字典,因为比较多,这里不作详细解释
//这个函数的作用是把共享内存映射到调用进程的地址空间中去。

//系统调用:
int shmdt(void *shmaddr);//当一个进程不需要共享内存段时,它将会把内存段从其他地址空间中脱离。

总结:
   1:共享内存中的数据,从来不写入到实际的磁盘文件中去:共享内存机制实际是通过映射特殊文件系统shm中的文件实现的,文件系统的安装点在交换分区上,系统重新引导后,所有的内容都丢失:
   2:共享内存是随内核持续的,即使所有访问共享内存的进程都已经正常终止,共享内存去依然存在。

5:结语

   学习路漫漫,我们仍需负重前行……今天的内容就到此为止了,还没有收藏的小伙伴们赶紧收藏吧!
下一章:纯新多线程【代码完整版】

你可能感兴趣的:(C/C++程序员进阶课堂,多进程,linux,c语言)