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

一.多进程服务器端

(一)进程概念及应用

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

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;elseval+=2;if(pid==0)std::cout<<"子进程:"<<"val:"<<val<<"  index:"<<index<<std::endl;elsestd::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.mzph.cn/news/60938.shtml

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

相关文章

记录--解决前端内存泄漏:问题概览与实用解决方案

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 内存泄漏是前端开发中的一个常见问题&#xff0c;可能导致项目变得缓慢、不稳定甚至崩溃。在本文中&#xff0c;我们将深入探讨在JavaScript、Vue和React项目中可能导致内存泄漏的情况&#xff0c;并提…

xml和json互转工具类

分享一个json与xml互转的工具类&#xff0c;非常好用 一、maven依赖 <!-->json 和 xm 互转</!--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency&g…

使用kafka还在依赖Zookeeper,kraft模式了解下

Kafka的Kraft模式 概述 ​ Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer&#xff0c;以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器…

Java连接websocket优雅断线、重连功能

为了实现优雅重连和重试&#xff0c;您需要在代码中添加一些逻辑来处理连接失败或断开连接的情况。 实现代码如下&#xff1a; import javax.websocket.*; import java.io.IOException;ClientEndpoint public class WebSocketClientEndpoint {private Session userSession n…

设备报修系统有什么用?企业如何提高维修效率和质量?

在数字化时代&#xff0c;基于人工智能和大数据技术的设备报修系统已经成为企业提高服务质量和效率的重要手段。这种系统可以为用户提供方便快捷的报修方式&#xff0c;例如通过扫描设备上的二维码或通过公众号、企业微信、钉钉等平台提交报修请求。这种报修系统不仅可以提高故…

香港服务器快还是台湾服务器快?

​  基于机房位置不同&#xff0c;香港服务器相对于台湾服务器在访问速度方面有一定的优势。香港服务器拥有CN2线路&#xff0c;因此访问速度较快。在网络服务商方面&#xff0c;中华电信等台湾服务商提供的带宽也具有很高的性价比。 香港服务器对大陆用户的影响 对于大陆用户…

如何增长LLM推理token,从直觉到数学

背景&#xff1a; 最近大模型输入上文长度增长技术点的研究很火。为何要增长token长度,为何大家如此热衷于增长输入token的长度呢&#xff1f;其实你如果是大模型比价频繁的使用者&#xff0c;这个问题应该不难回答。增长了输入token的长度&#xff0c;那需要多次出入才能得到…

软考:中级软件设计师:信息系统的安全属性,对称加密和非对称加密,信息摘要,数字签名技术,数字信封与PGP

软考&#xff1a;中级软件设计师:信息系统的安全属性 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准…

W5500-EVB-PICO通过SNTP获取网络时间(十一)

前言 上一章我们用W5500_EVB_PICO 开发板做Ping数据测试IP检测连通性&#xff0c;那么本章我们进行W5500_EVB_PICO SNTP的测试。 什么是NTP&#xff1f; NTP(Network Time Protocol&#xff09;网络时间协议基于UDP&#xff0c;用于网络时间同步的协议&#xff0c;使网络中的计…

element-plus指定el-date-picker的弹出框位置

此处记录一下,通过popper-options指定popper出现的位置

2、QT的信号与槽

一、什么是信号与槽 一个对象发送一个信号出去&#xff0c;另外一个对象接收到该信号后&#xff0c;会触发相应的槽函数 二、信号与槽的语法 connect(信号的发送者&#xff0c;SIGNAL(信号名称),信号的接收者,SLOT(槽函数)); 1、写法&#xff1a; QT 4 的写法 connect(sende…

anaconda环境迁移

conda环境迁移第一步 进入anaconda安装文件夹&#xff0c;然后进入envs文件夹&#xff0c;下面的每一个文件夹都是你创建的环境&#xff0c; 准备一个u盘之类的&#xff0c;把整个文件夹复制下来&#xff0c;然后打开另外一台机器&#xff0c;把同样的文件夹复制到同样的文件夹…

Maven的profiles多环境配置

一个项目通常都会有多个不同的运行环境&#xff0c;例如开发环境&#xff0c;测试环境、生产环境等。而不同环境的构建过程很可能是不同的&#xff0c;例如数据源配置、插件、以及依赖的版本等。每次将项目部署到不同的环境时&#xff0c;都需要修改相应的配置&#xff0c;这样…

0830hw

1.2.链式队列 head.h #include <myhead.h> typedef int datatype; typedef struct seq {union{datatype data;int len;};struct seq *next; }seq,*S; typedef struct PP {S front;S rear; }P; P *create(); void input_tail(P *p,datatype n); void pop_head(P *p); vo…

postgresql-日期函数

postgresql-日期函数 日期时间函数计算时间间隔获取时间中的信息截断日期/时间创建日期/时间获取系统时间CURRENT_DATE当前事务开始时间 时区转换 日期时间函数 PostgreSQL 提供了以下日期和时间运算的算术运算符。 计算时间间隔 age(timestamp, timestamp)函数用于计算两…

恢复已删除的git分支

1.打开对应项目文件夹目录,在目录下执行git命令 2.执行命令 git reflog --dateiso , 找到最后一次commit 的id 3. 执行git checkout -b 新建分支名称 commitId 就会基于commitId这次提交时工作区新建一个分支&#xff0c;就能达到我们找到删除分支的代码效果。 4.直接看ide…

ABB PCD231B101励磁控制模块

电磁励磁控制&#xff1a; PCD231B101 模块专门设计用于电磁励磁设备的控制&#xff0c;以确保发电机的励磁电流和电压维持在合适的水平。 多通道控制&#xff1a; 这种模块通常具有多个控制通道&#xff0c;可用于同时监测和控制多台电力发电机。 通讯接口&#xff1a; PCD2…

二叉树的前序遍历

目录 题目题目要求示例 解答方法一、实现思路时间复杂度和空间复杂度代码 方法二、实现思路时间复杂度和空间复杂度代码 题目 二叉树的前序遍历 题目要求 题目链接 示例 解答 方法一、 递归法 实现思路 使用递归依次将该结点的数据&#xff0c;该结点的左子树的数据&am…

0202hdfs的shell操作-hadoop-大数据学习

文章目录 1 进程启停管理2 文件系统操作命令2.1 HDFS文件系统基本信息2.2 介绍2.3 创建文件夹2.4 查看指定文件夹下的内容2.5 上传文件到HDFS2.6 查看HDFS文件内容2.7 下载HDFS文件2.8 HDFS数据删除操作 3 HDFS客户端-jetbrians产品插件3.1 Big Data Tools 安装3.2 配置windows…

WPF+Prism+WebApi 学习总结

一、基本概念 WPF:WPF&#xff08;Windows Presentation Foundation&#xff09;是&#xff08;微软推出的&#xff09;基于Windows的用户界面框架&#xff0c;提供了统一的编程模型&#xff0c;语言和框架&#xff0c;做到了分离界面设计人员与开发人员的工作&#xff1b;WPF…