光电工程东莞网站建设,济南网站制作0531soso,网页专题设计,python网站开发集成环境一.多进程服务器端
#xff08;一#xff09;进程概念及应用 利用之前学习到的内容#xff0c;我们的服务器可以按照顺序处理多个客户端的服务请求。在客户端和服务时间增长的情况下#xff0c;服务器就不足以满足需求了。
1.两种类型的服务器端
#xff08;1#xff…一.多进程服务器端
一进程概念及应用 利用之前学习到的内容我们的服务器可以按照顺序处理多个客户端的服务请求。在客户端和服务时间增长的情况下服务器就不足以满足需求了。
1.两种类型的服务器端
1普通服务器当有100个客户端连接请求到来时假设每个请求的受理时间为1s那么第50个请求需要等待50s第100个请求需要等待100s
2并发服务器所有客户端的连接请求受理时间都不超过1s单平均服务时间2-3s。 很明显并发服务器处理高并发量的情况效率更高。 2.并发服务器端的实现方法 多进程服务器通过创建多个进程提供服务。 多路复用服务器通过捆绑并统一管理 I/O 对象提供服务。 多线程服务器通过生成与客户端等量的线程提供服务。 3.理解进程Precoess
进程Process是计算机中的一个术语指的是正在运行中的程序实例。在操作系统中每个进程都有自己独立的内存空间和资源它们之间相互隔离并且可以独立执行。
每个进程可以包含一个或多个线程线程是进程内的执行单元负责执行进程的指令。不同的进程之间可以并发执行相互之间独立运行彼此不会干扰。
进程有以下几个特点
独立性每个进程拥有自己的地址空间和资源运行时相互独立一个进程的崩溃不会影响其他进程。并发性多个进程可以同时运行由操作系统进行调度和管理利用多核处理器实现并行处理。隔离性不同进程之间的内存空间相互隔离一个进程无法直接访问另一个进程的数据和资源需要通过特定的机制进行通信和共享。可抢占性操作系统可以根据优先级和时间片轮转等策略暂停当前进程的执行并将CPU分配给其他进程以实现公平调度和资源利用。
进程是操作系统中重要的概念它为程序的执行提供了一个独立和可控的环境。通过进程操作系统可以同时运行多个应用程序实现资源的合理分配和管理。
生活中有许多例子可以说明进程的概念。下面是几个常见的例子 煮饭过程将烹饪一顿饭比作一个进程。在煮饭的过程中你需要准备食材、洗切处理、点火、加热、炒煮等一系列步骤。每个步骤都是相对独立的但又相互关联最终完成一道美味的饭菜。 打印文件当你要打印一个文件时你会选择打印命令并发送给打印机。打印机会创建一个打印进程它负责从计算机接收数据、解析文件格式、生成打印页面并将页面发送到打印机进行输出。同时你可以进行其他操作如编辑文档或浏览网页这些操作与打印进程并行执行。 路上的交通将路上的车辆比作进程。在拥挤的道路上每辆车都是一个独立的进程它们之间相互独立运行但也受到交通规则和信号灯的控制。每辆车根据自己的路径和目的地进行行驶通过调度和协调交通系统实现了车辆的并发运行和道路资源的合理利用。 整个工业生产过程在一个工厂中生产线上的各个环节可以看作是不同的进程。例如原材料的采购、加工制造、装配、质量检测等环节都是相对独立的进程它们按照一定的顺序和流程进行并最终完成产品的制造。
这些例子说明了生活中进程的存在和应用。无论是在计算机系统中还是在日常生活中进程都扮演着协调和管理任务的重要角色实现了多个任务之间的并发执行和资源的合理利用。 4.进程ID
进程IDProcess ID也称为PID是操作系统中用来唯一标识一个正在运行的进程的数字标识符。每个进程在创建时都会被分配一个独特的PID。
pa au 查看当前运行的所有进程
进程ID的作用有以下几个方面 进程标识通过PID操作系统可以准确地标识和区分不同的进程。不同的进程具有不同的PID使得操作系统可以对它们进行管理、调度和资源分配。 进程控制操作系统可以使用PID来控制进程的创建、终止和暂停等操作。通过指定PID可以准确地选择目标进程并执行相应的操作。 进程通信在进程间进行通信时PID常被用作目标进程的标识符。发送进程可以通过目标进程的PID将消息或数据传递给指定的进程。 资源管理各个系统资源如内存、文件、网络连接等都与特定的进程相关联。通过PID操作系统可以将资源与相应的进程关联起来并进行有效的资源管理和保护。
需要注意的是PID是动态分配的当一个进程终止后其PID可能会被重新分配给新创建的进程。因此PID只在进程的生命周期内是唯一的。 5.通过 fork() 函数创建进程 在操作系统中可以使用fork()函数来创建一个新的进程。fork()是一个系统调用其功能是复制当前进程称为父进程创建一个新的进程称为子进程。子进程是父进程的副本它继承了父进程的代码、数据和资源。
具体使用方法如下
在程序中调用fork()函数。fork()函数没有参数返回值为整型。fork()函数的返回值不同于父进程和子进程。在父进程中fork()返回子进程的PID大于0在子进程中fork()返回0如果fork()调用失败返回一个负值表示错误。父进程和子进程之后的代码是完全独立执行的。根据fork()函数的返回值可以在程序中使用条件语句或其他逻辑来区分父进程和子进程的执行路径。子进程可以通过修改自己的代码和数据执行不同的任务。父进程和子进程之间共享打开的文件描述符和某些系统资源但是它们有各自独立的运行环境和内存空间。
#includeiostream
#includeunistd.h
int val10;
int main(){pid_t pidfork();int index25;val,index5;if(pid-1){//fork调用失败std::cout fork调用失败std::endl;return 1;}else if(pid0)index10;elseval2;if(pid0)std::cout子进程val:val index:indexstd::endl;elsestd::cout父进程val:val index:indexstd::endl
;return 0;
} 可以看出父子进程的变量都是单独区分开的修改并不会相互影响。
通过fork()函数创建的子进程继承了父进程的大部分状态包括变量值、打开的文件、进程优先级等。子进程可以独立执行其他任务这样就实现了并发执行多个进程的能力。
需要注意的是fork()函数的调用可能会导致操作系统创建新的进程和分配额外的资源。因此在使用fork()函数时应该注意合理使用系统资源避免过多创建进程导致系统负载过重。 二进程与僵尸进程
进程是操作系统中正在运行的程序的实例它具有独立的执行环境和资源。当一个进程完成了它的任务并且终止了但其父进程尚未通过wait()或waitpid()等系统调用来获取该子进程的状态信息时这个已经终止但尚未被回收的进程就成为僵尸进程。
僵尸进程是一种特殊的进程状态其主要特点包括
僵尸进程处于终止状态即进程已经执行完毕但它的进程描述符仍然存在于系统中。父进程尚未对其进行处理父进程还没有使用wait()或waitpid()等系统调用来获取子进程的退出状态信息。僵尸进程不再执行任何代码僵尸进程不再占用CPU时间片也不再占用其他系统资源。
产生僵尸进程的常见情况是父进程在创建子进程后没有及时处理子进程的终止状态。这可能是因为父进程疏忽、崩溃或者被其他任务所占用而没有处理子进程。
虽然僵尸进程本身并不会导致系统性能问题但过多的僵尸进程可能会浪费系统资源。因此需要及时清理僵尸进程。父进程可以通过以下方式处理僵尸进程
使用wait()或waitpid()等系统调用父进程可以主动调用wait()或waitpid()等系统调用来获取子进程的退出状态信息从而使子进程成为终止状态释放其占用的系统资源。使用信号处理机制父进程可以通过注册SIGCHLD信号处理函数当收到这个信号时处理僵尸进程的终止状态。
另外操作系统也会提供一些机制来自动回收僵尸进程例如Linux中的init进程PID为1会负责收养孤儿进程和回收僵尸进程。
在编写程序时父进程应该及时处理子进程的退出状态以避免过多的僵尸进程积累。 1.子进程的终止方式
1正常退出子进程可以在执行完任务后通过调用exit()函数来正常退出。exit()函数会终止当前进程并将退出状态传递给父进程。
#include stdlib.hint main() {// 子进程执行任务// ...// 正常退出exit(EXIT_SUCCESS);
}2异常退出子进程也可以通过调用abort()函数或触发一个信号来异常退出。abort()函数会立刻终止进程触发SIGABRT信号而信号处理程序则会默认终止进程。
#include stdlib.hint main() {// 子进程执行任务// ...// 异常退出abort();// 或者raise(SIGABRT);
}3返回值退出子进程可以通过在main函数中返回一个整数值来退出。这个整数值会被传递给父进程作为退出状态码。
int main() {// 子进程执行任务// ...// 返回值退出return 0;
}4exec()系列函数子进程可以使用exec()系列函数来加载一个新的程序镜像从而替换当前进程的内容。一旦调用exec()成功子进程就会停止原有的代码执行而是开始执行新程序的代码。这种方式不是直接终止进程而是将子进程转变为新的程序。
#include unistd.hint main() {// 子进程执行任务// ...// 加载新程序execl(/bin/ls, ls, -l, NULL);
}无论子进程是通过哪种方式终止父进程都可以通过使用 wait() 或 waitpid() 等系统调用来获取子进程的退出状态信息并进行相应的处理。这样可以确保父进程及时清理僵尸进程并释放相应的资源。 2.销毁僵尸进程
1wait
#includeiostream
#includeunistd.h
#includesys/wait.h
using namespace std;
int main(){int status;pid_t pidfork();if(pid-1){std::cout父进程创建失败std::endl;return 1;}else if(pid0)return 3;//返回终止else{coutchild PID: pidendl;pidfork();if(pid0)exit(7);//exit函数终止else{coutchild PID: pidendl;wait(status);//将之前终止的子进程相关信息保存到status变量同时子进程完全销毁if(WIFEXITED(status))//判断是否正常终止如果正常退出下面子进程返回值coutchild send one:WEXITSTATUS(status)endl;wait(status);//第二个终止的子进程if(WIFEXITED(status))coutchild send two:WEXITSTATUS(status)endl;sleep(30);}}return 0;
}return 或是 exit 都是把进程终止但是子进程的系统资源还没有回收父进程通过 wait 函数释放子进程所占据的资源。
注意调用 wait 函数时如果没有已终止的子进程那么程序将阻塞Blocking直到子进程终止因此需谨慎使用。 2waitpid
调用 waitpid 函数时程序不会阻塞。
#includeiostream
#includesys/types.h
#includesys/wait.h
#includeunistd.h
using namespace std;
int main(){pid_t pidfork();//创建子进程int status;if(pid0){//子进程sleep(15);return 24;}else{//父进程while(!waitpid(-1,status,WNOHANG)){//当没有子进程终止时保持循环sleep(3);//休眠三秒coutsleep 3secendl;}//子进程终止后资源被waitpid回收if(WIFEXITED(status))//判断子进程是否正常退出 coutchild send :WEXITSTATUS(status)endl;}return 0;
}三信号处理