day-06 多进程服务器端 -- 进程间通信

news2024/12/24 8:40:19

一.多进程服务器端

(一)进程概念及应用

        利用之前学习到的内容,我们的服务器可以按照顺序处理多个客户端的服务请求。在客户端和服务时间增长的情况下,服务器就不足以满足需求了。

1.两种类型的服务器端

(1)普通服务器:当有100个客户端连接请求到来时,假设每个请求的受理时间为1s,那么第50个请求需要等待50s,第100个请求需要等待100s

(2)并发服务器:所有客户端的连接请求受理时间都不超过1s,单平均服务时间2-3s。

        很明显并发服务器处理高并发量的情况效率更高。

2.并发服务器端的实现方法

        多进程服务器:通过创建多个进程提供服务。

        多路复用服务器:通过捆绑并统一管理 I/O 对象提供服务。

        多线程服务器:通过生成与客户端等量的线程提供服务。

3.理解进程(Precoess)

进程(Process)是计算机中的一个术语,指的是正在运行中的程序实例。在操作系统中,每个进程都有自己独立的内存空间和资源,它们之间相互隔离,并且可以独立执行。

每个进程可以包含一个或多个线程,线程是进程内的执行单元,负责执行进程的指令。不同的进程之间可以并发执行,相互之间独立运行,彼此不会干扰。

进程有以下几个特点:

  1. 独立性:每个进程拥有自己的地址空间和资源,运行时相互独立,一个进程的崩溃不会影响其他进程。
  2. 并发性:多个进程可以同时运行,由操作系统进行调度和管理,利用多核处理器实现并行处理。
  3. 隔离性:不同进程之间的内存空间相互隔离,一个进程无法直接访问另一个进程的数据和资源,需要通过特定的机制进行通信和共享。
  4. 可抢占性:操作系统可以根据优先级和时间片轮转等策略,暂停当前进程的执行,并将CPU分配给其他进程,以实现公平调度和资源利用。

进程是操作系统中重要的概念,它为程序的执行提供了一个独立和可控的环境。通过进程,操作系统可以同时运行多个应用程序,实现资源的合理分配和管理。

生活中有许多例子可以说明进程的概念。下面是几个常见的例子

  1. 煮饭过程:将烹饪一顿饭比作一个进程。在煮饭的过程中,你需要准备食材、洗切处理、点火、加热、炒煮等一系列步骤。每个步骤都是相对独立的,但又相互关联,最终完成一道美味的饭菜。

  2. 打印文件:当你要打印一个文件时,你会选择打印命令并发送给打印机。打印机会创建一个打印进程,它负责从计算机接收数据、解析文件格式、生成打印页面,并将页面发送到打印机进行输出。同时,你可以进行其他操作,如编辑文档或浏览网页,这些操作与打印进程并行执行。

  3. 路上的交通:将路上的车辆比作进程。在拥挤的道路上,每辆车都是一个独立的进程,它们之间相互独立运行,但也受到交通规则和信号灯的控制。每辆车根据自己的路径和目的地进行行驶,通过调度和协调,交通系统实现了车辆的并发运行和道路资源的合理利用。

  4. 整个工业生产过程:在一个工厂中,生产线上的各个环节可以看作是不同的进程。例如,原材料的采购、加工制造、装配、质量检测等环节都是相对独立的进程,它们按照一定的顺序和流程进行,并最终完成产品的制造。

这些例子说明了生活中进程的存在和应用。无论是在计算机系统中还是在日常生活中,进程都扮演着协调和管理任务的重要角色,实现了多个任务之间的并发执行和资源的合理利用。

4.进程ID

进程ID(Process ID),也称为PID,是操作系统中用来唯一标识一个正在运行的进程的数字标识符。每个进程在创建时都会被分配一个独特的PID。

  • pa au 查看当前运行的所有进程

进程ID的作用有以下几个方面:

  1. 进程标识:通过PID,操作系统可以准确地标识和区分不同的进程。不同的进程具有不同的PID,使得操作系统可以对它们进行管理、调度和资源分配。

  2. 进程控制:操作系统可以使用PID来控制进程的创建、终止和暂停等操作。通过指定PID,可以准确地选择目标进程并执行相应的操作。

  3. 进程通信:在进程间进行通信时,PID常被用作目标进程的标识符。发送进程可以通过目标进程的PID将消息或数据传递给指定的进程。

  4. 资源管理:各个系统资源,如内存、文件、网络连接等,都与特定的进程相关联。通过PID,操作系统可以将资源与相应的进程关联起来,并进行有效的资源管理和保护。

需要注意的是,PID是动态分配的,当一个进程终止后,其PID可能会被重新分配给新创建的进程。因此,PID只在进程的生命周期内是唯一的。

5.通过 fork() 函数创建进程

        在操作系统中,可以使用fork()函数来创建一个新的进程。fork()是一个系统调用,其功能是复制当前进程(称为父进程),创建一个新的进程(称为子进程)。子进程是父进程的副本,它继承了父进程的代码、数据和资源。

具体使用方法如下:

  • 在程序中调用fork()函数。fork()函数没有参数,返回值为整型。
  • fork()函数的返回值不同于父进程和子进程。在父进程中,fork()返回子进程的PID(大于0);在子进程中,fork()返回0;如果fork()调用失败,返回一个负值表示错误。
  • 父进程和子进程之后的代码是完全独立执行的。根据fork()函数的返回值,可以在程序中使用条件语句或其他逻辑来区分父进程和子进程的执行路径。
  • 子进程可以通过修改自己的代码和数据,执行不同的任务。父进程和子进程之间共享打开的文件描述符和某些系统资源,但是它们有各自独立的运行环境和内存空间。
#include<iostream>
#include<unistd.h>
int val=10;
int main(){
	pid_t pid=fork();
	int index=25;
	val++,index+=5;
	if(pid==-1){//fork调用失败
		std::cout<<" fork调用失败"<<std::endl;
		return 1;
	}
	else if(pid==0)
		index+=10;
	else
		val+=2;

	if(pid==0)
		std::cout<<"子进程:"<<"val:"<<val<<"  index:"<<index<<std::endl;
	else
		std::cout<<"父进程:"<<"val:"<<val<<"  index:"<<index<<std::endl
;

	return 0;
}

         可以看出,父子进程的变量都是单独区分开的,修改并不会相互影响。

通过fork()函数创建的子进程继承了父进程的大部分状态,包括变量值、打开的文件、进程优先级等。子进程可以独立执行其他任务,这样就实现了并发执行多个进程的能力。

需要注意的是,fork()函数的调用可能会导致操作系统创建新的进程和分配额外的资源。因此,在使用fork()函数时应该注意合理使用系统资源,避免过多创建进程导致系统负载过重。

 

(二)进程与僵尸进程

进程是操作系统中正在运行的程序的实例,它具有独立的执行环境和资源。当一个进程完成了它的任务,并且终止了,但其父进程尚未通过wait()或waitpid()等系统调用来获取该子进程的状态信息时,这个已经终止但尚未被回收的进程就成为僵尸进程。

僵尸进程是一种特殊的进程状态,其主要特点包括:

  1. 僵尸进程处于终止状态:即进程已经执行完毕,但它的进程描述符仍然存在于系统中。
  2. 父进程尚未对其进行处理:父进程还没有使用wait()或waitpid()等系统调用来获取子进程的退出状态信息。
  3. 僵尸进程不再执行任何代码:僵尸进程不再占用CPU时间片,也不再占用其他系统资源。

产生僵尸进程的常见情况是,父进程在创建子进程后,没有及时处理子进程的终止状态。这可能是因为父进程疏忽、崩溃或者被其他任务所占用而没有处理子进程。

虽然僵尸进程本身并不会导致系统性能问题,但过多的僵尸进程可能会浪费系统资源。因此,需要及时清理僵尸进程。父进程可以通过以下方式处理僵尸进程:

  1. 使用wait()或waitpid()等系统调用:父进程可以主动调用wait()或waitpid()等系统调用来获取子进程的退出状态信息,从而使子进程成为"终止"状态,释放其占用的系统资源。
  2. 使用信号处理机制:父进程可以通过注册SIGCHLD信号处理函数,当收到这个信号时,处理僵尸进程的终止状态。

另外,操作系统也会提供一些机制来自动回收僵尸进程,例如Linux中的"init"进程(PID为1)会负责收养孤儿进程和回收僵尸进程。

在编写程序时,父进程应该及时处理子进程的退出状态,以避免过多的僵尸进程积累。

1.子进程的终止方式:

(1)正常退出:子进程可以在执行完任务后通过调用exit()函数来正常退出。exit()函数会终止当前进程,并将退出状态传递给父进程。

#include <stdlib.h>

int main() {
    // 子进程执行任务
    // ...

    // 正常退出
    exit(EXIT_SUCCESS);
}

(2)异常退出:子进程也可以通过调用abort()函数或触发一个信号来异常退出。abort()函数会立刻终止进程,触发SIGABRT信号,而信号处理程序则会默认终止进程。

#include <stdlib.h>

int main() {
    // 子进程执行任务
    // ...

    // 异常退出
    abort();
    // 或者
    raise(SIGABRT);
}

 

(3)返回值退出:子进程可以通过在main函数中返回一个整数值来退出。这个整数值会被传递给父进程作为退出状态码。

int main() {
    // 子进程执行任务
    // ...

    // 返回值退出
    return 0;
}

(4)exec()系列函数:子进程可以使用exec()系列函数来加载一个新的程序镜像,从而替换当前进程的内容。一旦调用exec()成功,子进程就会停止原有的代码执行,而是开始执行新程序的代码。这种方式不是直接终止进程,而是将子进程转变为新的程序。

#include <unistd.h>

int main() {
    // 子进程执行任务
    // ...

    // 加载新程序
    execl("/bin/ls", "ls", "-l", NULL);
}

无论子进程是通过哪种方式终止,父进程都可以通过使用 wait() 或 waitpid() 等系统调用来获取子进程的退出状态信息,并进行相应的处理。这样可以确保父进程及时清理僵尸进程,并释放相应的资源。

2.销毁僵尸进程

(1)wait
#include<iostream>
#include<unistd.h>
#include<sys/wait.h>
using namespace std;
int main(){
	int status;
	pid_t pid=fork();

	if(pid==-1){
		std::cout<<"父进程创建失败"<<std::endl;
		return 1;
	}
	else if(pid==0)
		return 3;//返回终止
	else{
		cout<<"child PID: "<<pid<<endl;
		pid=fork();
		if(pid==0)
			exit(7);//exit函数终止
		else{
			cout<<"child PID: "<<pid<<endl;
			wait(&status);//将之前终止的子进程相关信息保存到status变量,同时子进程完全销毁
			if(WIFEXITED(status))//判断是否正常终止,如果正常退出,下面子进程返回值
				cout<<"child send one:"<<WEXITSTATUS(status)<<endl;
			wait(&status);//第二个终止的子进程
			if(WIFEXITED(status))
                                cout<<"child send two:"<<WEXITSTATUS(status)<<endl;
			sleep(30);
		}
	}
	return 0;
}

        return 或是 exit 都是把进程终止,但是子进程的系统资源还没有回收,父进程通过 wait 函数释放子进程所占据的资源。

注意:调用 wait 函数时,如果没有已终止的子进程,那么程序将阻塞(Blocking)直到子进程终止,因此需谨慎使用。

(2)waitpid

调用 waitpid 函数时,程序不会阻塞。

#include<iostream>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
using namespace std;
int main(){
	pid_t pid=fork();//创建子进程
	int status;

	if(pid==0){//子进程
		sleep(15);
		return 24;
	}
	else{//父进程
		while(!waitpid(-1,&status,WNOHANG)){//当没有子进程终止时,保持循环
			sleep(3);//休眠三秒
			cout<<"sleep 3sec"<<endl;
		}//子进程终止后,资源被waitpid回收


		if(WIFEXITED(status))//判断子进程是否正常退出			
            cout<<"child send :"<<WEXITSTATUS(status)<<endl;
	}
	return 0;
}

 

(三)信号处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/957706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安全基础 --- https详解(02)、cookie和session、同源和跨域

https详解&#xff08;02&#xff09;--- 数据包扩展 Request --- 请求数据包Response --- 返回数据包 若出现代理则如下图&#xff1a; Proxy --- 代理服务器 &#xff08;1&#xff09;http和https的区别 http明文传输&#xff0c;数据未加密&#xff1b;http页面响应速度…

【Java 动态数据统计图】动态X轴二级数据统计图思路Demo(动态,排序,动态数组(重点推荐:难)九(131)

需求&#xff1a; 1.有一组数据集合&#xff0c;数据集合中的数据为动态&#xff1b; 举例如下&#xff1a; [{province陕西省, city西安市}, {province陕西省, city咸阳市}, {province陕西省, city宝鸡市}, {province陕西省, city延安市}, {province陕西省, city汉中市}, {pr…

用了这么久SpringBoot却还不知道的一个小技巧

前言 你可能调第三方接口喜欢启动application&#xff0c;修改&#xff0c;再启动&#xff0c;再修改&#xff0c;顺便还有个不喜欢写JUnitTest的习惯。 你可能有一天想要在SpringBoot启动后&#xff0c;立马想要干一些事情&#xff0c;现在没有可能是你还没遇到。 那么SpringB…

windows10默认浏览器总是自动更改为Edge浏览器

在设置的默认应用设置中把默认浏览器改为chrome或其他之后他自动又会改回Edge。不得不说*软真的狗。 解决办法&#xff1a; 后来发现在Edge浏览器的设置中有这么一个选项&#xff0c;会很无耻的默认是Edge。把它关掉后重新设置就行了。

02. 计算机的组成

1. 从手机和电脑开始 要是20年前&#xff0c;大家对于计算机还很陌生&#xff0c;但是现在手机和电脑已经非常普及了&#xff0c;即使对于偏远地区可能有人没有接触过电脑&#xff0c;但是手机肯定都用过。其实手机和电脑都是计算机&#xff01; 1.1 手机的8G256G是什么意思?…

2D-2D对极几何中的基本矩阵、本质矩阵和单应矩阵

本文主要参考高翔博士的视觉SLAM十四讲第二版中的7.3章节内容。文章目录 1 对极约束2 本质矩阵E3 单应矩阵 1 对极约束 现在&#xff0c;假设我们从两张图像中得到了一对配对好的特征点&#xff0c;如图7.9所示&#xff08;假如后面我们有若干对这样的匹配点&#xff0c;根据这…

IDEA打开一个项目时,idea左侧project模式下,不显示项目工程目录的解决方法

在IDEA打开一个一个已有的项目chapter3时&#xff0c;idea左侧project模式下&#xff0c;左侧也没有project按钮&#xff0c;如下问题截图&#xff1a;&#xff08;ps:项目结构可以显示&#xff0c;但是src等目录不见&#xff09; 在网上查了一些方法&#xff1a; 1、解决办法…

移动端的概念

【移动端】 1. 什么是移动端 大前端时代&#xff1a; ​ 前端开发涉及的领域越来越多&#xff0c;如&#xff1a;PC端&#xff0c;移动端&#xff0c;小程序&#xff0c;App&#xff0c;甚至是物联网​ 大前端’的大字体现在地位重要&#xff0c;涉及领域众多​ 前后端完全分…

从零开始的Hadoop学习(五)| HDFS概述、shell操作、API操作

1. HDFS 概述 1.1 HDFS 产出背景及定义 1&#xff09;HDFS 产生背景 随着数据量越来越大&#xff0c;在一个操作系统存不下所有的数据&#xff0c;那么就分配到更多的操作系统管理的磁盘中&#xff0c;但是不方便管理和维护&#xff0c;迫切 需要一种系统来管理多台机器上的…

OpenCV(八):图像二值化

目录 1.固定值二值化 2.自适应阈值二值化 3.Android JNI完整代码 1.固定值二值化 固定阈值二值化是OpenCV中一种简单而常用的图像处理技术&#xff0c;用于将图像转换为二值图像。在固定阈值二值化中&#xff0c;像素值根据一个预定义的阈值进行分类&#xff0c;大于阈值的…

OFDM 系统在 AWGN 信道下对不同载波频率偏移 (CFO) 的 BER 灵敏度研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

软件测评国家标准概要总结

软件测试 软件测评是指针对软件功能、性能、用途使用价值等进行的评价和测试&#xff1b; 软件测评主要依靠标准是GB/T 25000.51-2016 系统与软件工程 系统与软件质量要求和评价&#xff08;SQuaRE&#xff09; 第51部分&#xff1a;就绪可用软件产品&#xff08;RUSP&#x…

基于JavaWeb和mysql实现校园订餐前后台管理系统(源码+数据库)

一、项目简介 本项目是一套基于JavaWeb和mysql实现网上书城前后端管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都…

小兔鲜儿---商品分类

目录 准备工作​ 渲染轮播图​ 一级分类​ 获取数据​ Tab 交互​ 二级分类​ 骨架屏​ 准备工作​ 参考效果 商品分类页中的广告位&#xff0c;可复用之前定义的轮播图组件 XtxSwiper。 静态结构 商品分类页静态结构&#xff1a; src/pages/category/category.vue …

Docsify + Gitalk详细配置过程讲解

&#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;开源建设者与全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#xff1a;Zeeland&#x1f4da; Github主页: Undertone0809 (Zeeland)&…

二进制安全虚拟机Protostar靶场 安装,基础知识讲解,破解STACK ZERO

简介 pwn是ctf比赛的方向之一&#xff0c;也是门槛最高的&#xff0c;学pwn前需要很多知识&#xff0c;这里建议先去在某宝上买一本汇编语言第四版&#xff0c;看完之后学一下python和c语言&#xff0c;python推荐看油管FreeCodeCamp的教程&#xff0c;c语言也是 pwn题目大部…

FastestDet:比yolov5更快!更强!全新设计的超实时Anchor-free目标检测算法(附源代码下载)...

关注并星标 从此不迷路 计算机视觉研究院 公众号ID&#xff5c;ComputerVisionGzq 学习群&#xff5c;扫码在主页获取加入方式 计算机视觉研究院专栏 作者&#xff1a;Edison_G 本篇文章转自于知乎——qiuqiuqiu&#xff0c;主要设计了一个新颖的轻量级网络&#xff01; 代码地…

【多线程】线程安全(重点)

文章目录 1. 观察线程不安全1.1 示例11.2 示例2 2. 线程不安全的原因2.1 修改共享数据2.2 原子性2.3 可见性2.4 顺序性 3. synchronized同步方法3.1 synchronized特性3.1.1 互斥3.1.2 刷新内存3.1.3 可重入 3.2 synchronized使用3.2.1 直接修饰普通方法3.2.2 修饰静态方法3.2.3…

开源照片管理服务LibrePhotos

本文是为了解决网友 赵云遇到的问题&#xff0c;顺便折腾的。虽然软件跑起来了&#xff0c;但是他遇到的问题&#xff0c;超出了老苏的认知。当然最终问题还是得到了解决&#xff0c;不过与 LibrePhotos 无关&#xff1b; 什么是 LibrePhotos ? LibrePhotos 是一个自托管的开源…

uniapp微信小程序用户隐私保护

使用wx.requirePrivacyAuthorize实现微信小程序用户隐私保护。 一、前言 微信小程序官方出了一个公告《关于小程序隐私保护指引设置的公告》。不整的话&#xff0c;后果很多授权无法使用&#xff0c;详见《小程序用户隐私保护指引内容介绍》 。 二、隐私相关设置 1、在 微信…