目录

操作系统实验一:进程管理

1.实验目的

2.实验内容

3.实验准备

3.1.1进程的含义

3.1.2进程的状态

3.1.3进程状态之间的转换

3.2 进程控制块PCB

3.2.1进程控制块的作用

3.2.2进程控制块的内容

3.2.3进程控制块(PCB)的组织形式

3.2.4进程控制原语

3.3进程的创建与撤销   *重点

3.3.1进程的创建

3.3.2进程的撤销

3.4进程的阻塞与唤醒

3.4.1进程的阻塞

3.4.2进程的唤醒

4.代码实现

4.1代码分解介绍

5.运行结果截图

(本文知识点较多,如时间较多可以详细看看第3章的知识点;如时间不多可直接点上方目录,直接看第4部分代码实现来理解)


操作系统实验一:进程管理


1.实验目的

1.理解进程的概念,明确进程和程序的区别

2.理解并发执行的实质

3.掌握进程的创建、睡眠、撤销等进程控制方法


2.实验内容

用C语言编写程序,模拟实现创建新的进程;查看运行进程;换出某个进程;杀死运行进程等功能。


3.实验准备

以下将分别介绍

进程的概念,以及进程的各类状态(就绪状态执行状态阻塞状态);

进程控制块PCB 作用内容信息

③进程的创建与撤销 (重点)

④进程的阻塞与唤醒(重点)


3.1.1进程的含义

进程是程序在一个数据集上的运行过程,是系统资源分配和调度的一个独立单位。一个程序在不同数据集上运行,乃至一个程序在同样数据集上的多次运行都是不同的进程。

3.1.2进程的状态

通常情况下,一个进程必须具有就绪执行阻塞三种基本状态。

(1)就绪状态

当进程已分配到除处理器(CPU)以外的所有必要资源后,只要再获得处理器就可以立即执行,此时进程的状态称为就绪状态。

在一个系统里,可以有多个进程同时处于就绪状态,通常把这些就绪进程排成一个或多个队列,称为就绪队列。

(2)执行状态

处于就绪状态的进程一旦获得了处理器(分配有处理器资源),就可以运行,进程状态也就处于执行状态。在单处理器系统中,只能有一个进程处于执行状态,在多处理器系统中,则可能有多个进程处于执行状态。

(3)阻塞状态

正在执行的进程因为发生某些事件(如请求输入输出、申请额外空间等)而暂停运行,这种受阻暂停的状态称为阻塞状态,也可以称为等待状态。通常将处于阻塞状态的进程排成一个队列,称为阻塞队列。在有些系统中,也会按阻塞原因的不同将处于阻塞状态的进程排成多个队列。

拓展

除了进程的3种基本状态外,在很多系统为了更好地描述进程的状态变化,又增加了两种状态。

     I新状态

    当一个新进程刚刚建立,还未将其放入就绪队列的状态,称为新状态。(例如一个,人刚开始接受教育,此时就可以称其处于新状态)

     II终止状态

    当一个进程已经正常结束或异常结束,操作系统已将其从系统队列中移出,但尚未撒消,这时称为终止状态


3.1.3进程状态之间的转换


3.2 进程控制块PCB

3.2.1进程控制块的作用

进程控制块是构成进程实体的重要组成部分,是操作系统中最重要的记录型数据,在进程控制块PCB中记录了操作系统所需要的、用于描述进程情况及控制进程运行所需要的全部信息。通过PCB,能够使得原来不能独立运行的程序(数据),成为一个可以独立运行的基本单位,一个能够并发执行的进程。换句话说,在进程的整个生命周期中,操作系统都要通过进程的PCB来对并发执行的进程进行管理和控制,进程控制块是系统对进程控制采用的数据结构,系统是根据进程的PCB而感知进程是否存在。所以,进程控制块是进程存在的唯一标志。当系统创建一个新进程时,就要为它建立一个PCB;进程结束时,系统又回收其PCB,进程也随之消亡。

3.2.2进程控制块的内容

进程控制块主要包括以下四个方面的内容:

(1)进程标识信息

----进程标识符用于标识一个进程,通常又分外部标识符和内部标识符两种。

(2)说明信息

----说明信息是有关进程状态等一些与进程调度有关的信息,它包括:①进程状态  ②进程优先权  ③与进程调度所需的其他信息  ④阻塞事件

(3)现场信息(处理器状态信息)

----现场信息是用于保留进程存放在处理器中的各种信息。主要由处理器内的各个寄存器的内容组成。尤其是当执行中的进程暂停时,这些寄存器内的信息将被保存在PCB里,当该进程获得重新执行时,能从上次停止的地方继续执行

(4)管理信息(进程控制信息)

进程控制信息主要分四方面:

程序和数据的地址 它是指该进程的程序和数据所在的主存和外存地址再次执行时,能够找到程序和数据
进程同步和通信机制 它是指实现进程同步和进程通信时所采用的机制、指针、信号量等
资源清单 该清单中存放有除了CPU以外,进程所需的全部资源和已经分配到的资源
链接指针 它将指向该进程所在队列的下一个进程的PCB的首地址

3.2.3进程控制块(PCB)的组织形式

在一个系统中,通常拥有数十个、数百个乃至数千个PCB,为了能对它们进行有效的管理,就必须通过适当的方式将它们组织起来,日前常用的组织方式有链接方式和索引方式两种。.

(1)链接方式

把具有相同状态的PCB,用链接指针链接成队列,如就绪队列、阻塞队列和空闲队列等。就绪队列中的PCB将按照相应的进程调度算法进行排序。而阻塞队列也可以根据阻塞原因的不同,将处于阻塞状态的进程的PCB,排成等待I/O队列、等待主存队列等多个队列。此外,系统主存的PCB区中空闲的空间将排成空闲队列,以方便进行PCB的分配与回收。

(2)索引方式

系统根据各个进程的状态,建立不同索引表,例如就绪索引表、阻塞索引表等。并把各个索引表在主存的首地址记录在主存中的专用单元里,也可以称为表指针。在每个索引表的表目中,记录着具有相同状态的各个PCB在表中的地址。


3.2.4进程控制原语

原语是指具有特定功能的不可被中断的过程。它主要用于实现操作系统的一 些专门控制操作。用于进程控制的原语有:

原语 作用
创建原语 用于为一个进程分配工作区和建立PCB,该进程为就绪状态
撤销原语 用于一个进程工作完后,收回它的工作区和PCB
阻塞原语 用于进程在运行过程中发生等待事件时,把进程的状态改为等待态
唤醒原语 用于当进程等待的事件结束时,把进程的状态改为就绪态

3.3进程的创建与撤销   *重点

3.3.1进程的创建

一旦操作系统发现了要求创建进程的事件后,便调用进程创建原按下列步骤创建一个新进程。

①为新进程分配惟一的进程标识符, 并从PCB队列中申请一个空闲PCB。

②为新进程的程序和数据,以及用户栈分配相应的主存空间及其他必要分配资源。

③初始化PCB中的相应信息,如标识信息、处理器信息、进程控制信息等。

④如果就绪队列可以接纳新进程,便将新进程加入到就绪队列中。

3.3.2进程的撤销

一旦操作系统发现了要求终止进程的事件后,便调用进程终止原语按下列步骤终止指定的进程。

①根据被终止进程的标识符,从PCB集合中检索该进程的PCB,读出进程状态。

②若该进程处于执行状态,则立即终止该进程的执行。

③若该进程有子孙进程,还要将其子孙进程终止。

④将该进程所占用的资源回收,归还给其父进程或操作系统。

⑤将被终止进程的PCB从所在队列中移出,并撤销该进程的PCB。


3.4进程的阻塞与唤醒

3.4.1进程的阻塞

一旦操作系统发现了要求阻塞进程的事件后,便调用进程阻塞原语,按下列步骤阻塞指定的进程。

①立即停止执行该进程。

②修改进程控制块中的相关信息。把进程控制块中的运行状态由“执行”状态改为“阻塞”状态,并填入等待的原因,以及进程的各种状态信息。

③把进程控制块插入到阻塞队列。根据阻塞队列的组织方式插入阻塞队列中。

④待调度程序重新调度,运行就绪队列中的其他进程。

3.4.2进程的唤醒

一旦操作系统发现了要求唤醒进程的事件后,便调用进程唤醒原语,按下列步骤唤醒指定的进程。

①从阻塞队列中找到该进程。

②修改该进程控制块的相关内容。把阻塞状态改为就绪状态,删除等待原因等。

③把进程控制块插入到就绪队列中。

④按照就绪队列的组织方式,把被唤醒的进程的进程控制块插入到就绪队列中。


4.代码实现

可成功运行代码如下

#include<stdio.h>
#include<stdlib.h>

#include<string.h>
struct jincheng_type{   //进程状态定义
int pid; //进程
int youxian; //进程优先级
int daxiao; //进程大小
int zhuangtai; //标志进程状态,0为不在内存,1为在内存,3为挂起
char info[10]; //进程内容
};
struct jincheng_type neicun[20];
int shumu=0,guaqi=0,pid,flag=0; //创建进程
void create(){
if(shumu>=20) printf("\n内存已满,请先换出或结束进程\n"); //内存容量大小设置为20
else{
int i;
printf("**当前默认一次性创建5个进程,内存容量20**");
for(i=0;i<5;i++) { //默认一次创建5个进程
//定位,找到可以还未创建的进程
if(neicun[i].zhuangtai==1) break; //如果找到的进程在内存则结束 ,初始设置都不在内存中(main函数中设置状态为0)
printf("\n请输入新进程pid\n");
scanf("%d",&(neicun[i].pid));
for(int j=0;j<i;j++)
if(neicun[i].pid==neicun[j].pid){
printf("\n该进程已存在\n");
return;
}
printf("请输入新进程优先级\n");
scanf("%d",&(neicun[i].youxian));
printf("请输入新进程大小\n");
scanf("%d",&(neicun[i].daxiao));
printf("请输入新进程内容\n");
scanf("%s",&(neicun[i].info));
//创建进程,使标记位为1
neicun[i].zhuangtai=1;
printf("进程已成功创建!");
shumu++;
}
}
} //进程运行状态检测
void run(){
printf("运行进程信息如下:");
for(int i=0;i<20;i++){
if(neicun[i].zhuangtai==1){
//如果进程正在运行,则输出此运行进程的各个属性值
printf("\n pid=%d ",neicun[i].pid);
printf(" youxian=%d ",neicun[i].youxian);
printf(" daxiao=%d ",neicun[i].daxiao);
printf(" zhuanbgtai=%d ",neicun[i].zhuangtai);
printf(" info=%s ",neicun[i].info);
flag=1;
}
}
if(!flag)
printf("\n当前没有运行进程!\n");
} //进程换出
void huanchu(){
if(!shumu){
printf("当前没有运行进程!\n");
return;
}
printf("\n请输入换出进程的ID值");
scanf("%d",&pid);
for(int i=0;i<20;i++){
//定位,找到要换出的进程,根据其状态进行相应处理
if(pid==neicun[i].pid) {
if(neicun[i].zhuangtai==1){
neicun[i].zhuangtai==2;
guaqi++;
printf("\n已经成功换出进程\n");
}
else if(neicun[i].zhuangtai==0) printf("\n要换出的进程不存在\n");
else printf("\n要换出的进程已被挂起\n");
flag=1;
break;
}
}
//找不到,则说明进程不存在
if(flag==0) printf("\n要换出的进程不存在\n");
} //结束(杀死)进程
void kill(){
if(!shumu){
printf("当前没有运行进程!\n");
return;
}
printf("\n输入杀死进程的ID值");
scanf("%d",&pid);
for(int i=0;i<20;i++){
//定位,找到所要杀死的进程,根据其状态做出相应处理
if(pid==neicun[i].pid){
neicun[i].zhuangtai = 0;
shumu--;
printf("\n已经成功杀死进程\n");
}
else if(neicun[i].zhuangtai==0) printf ("\n要杀死的进程不存在\n");
else printf("\n要杀死的进程已被挂起\n");
flag=1;
break;
}
//找不到,则说明进程不存在
if(!flag) printf("\n 要杀死的进程不存在\n"); } //唤醒进程
void huanxing(){
if (!shumu) {
printf("当前没有运行进程\n");
return;
}
if(!guaqi){
printf("\n当前没有挂起进程\n");
return;
}
printf("\n输入进程pid:\n");
scanf ("%d",&pid);
for (int i=0; i<20;i++) {
//定位,找到所要杀死的进程,根据其状态做相应处理
if (pid==neicun[i].pid) {
flag=false;
if(neicun[i].zhuangtai==2){
neicun[i].zhuangtai=1;
guaqi--;
printf ("\n已经成功唤醒进程\n");
}
else if(neicun[i].zhuangtai==0) printf("\n要唤醒的进程不存在\n");
else printf("\n要唤醒的进程已被挂起\n");
break;
}
}
//找不到,则说明进程不存在
if(flag) printf("\n要唤醒的进程不存在\n");
} //主函数
int main()
{
int n = 1;
int num;
//一开始所有进程都不在内存中
for(int i=0;i<20;i++)
neicun[i].zhuangtai = 0;
while(n){
printf("\n******************************************");
printf("\n* 进程演示系统 *");
printf("\n******************************************");
printf("\n*1.创建新的进程 2.查看运行进程 *");
printf("\n*3.换出某个进程 4.杀死运行进程 *");
printf("\n*5.唤醒某个进程 6.退出系统 *");
printf("\n******************************************");
printf("\n请选择(1~6)\n");
scanf("%d",&num);
switch(num){
case 1: create();break;
case 2: run();break;
case 3: huanchu(); break;
case 4: kill();break;
case 5: huanxing(); break;
case 6: printf("已退出系统");exit(0);
default: printf("请检查输入数值是否在系统功能中1~6");n=0;
}
flag = 0;//恢复标记
}
return 0;
}

4.1代码分解介绍

源程序中一共构造了5个函数方法来实现进程的创建、(运行进程的)显示、换出、结束(杀死)与唤醒。

4.1.1进程的创建

//创建进程
void create(){
if(shumu>=20) printf("\n内存已满,请先换出或结束进程\n"); //内存容量大小设置为20
else{
int i;
printf("**当前默认一次性创建5个进程,内存容量20**");
for(i=0;i<5;i++) { //默认一次创建5个进程
//定位,找到可以还未创建的进程
if(neicun[i].zhuangtai==1) break; //如果找到的进程在内存则结束 ,初始设置都不在内存中(main函数中设置状态为0)
printf("\n请输入新进程pid\n");
scanf("%d",&(neicun[i].pid));
for(int j=0;j<i;j++)
if(neicun[i].pid==neicun[j].pid){
printf("\n该进程已存在\n");
return;
}
printf("请输入新进程优先级\n");
scanf("%d",&(neicun[i].youxian));
printf("请输入新进程大小\n");
scanf("%d",&(neicun[i].daxiao));
printf("请输入新进程内容\n");
scanf("%s",&(neicun[i].info));
//创建进程,使标记位为1
neicun[i].zhuangtai=1;
printf("进程已成功创建!");
shumu++;
}
}
}

(默认设置内存容量大小为20,一次性创建5个进程;进程创建时首先检测进程状态,若为1则表明该进程此前已在内存中了,不可再创建)

4.1.2进程的显示(运行状态检测)

//进程运行状态检测
void run(){
printf("运行进程信息如下:");
for(int i=0;i<20;i++){
if(neicun[i].zhuangtai==1){
//如果进程正在运行,则输出此运行进程的各个属性值
printf("\n pid=%d ",neicun[i].pid);
printf(" youxian=%d ",neicun[i].youxian);
printf(" daxiao=%d ",neicun[i].daxiao);
printf(" zhuanbgtai=%d ",neicun[i].zhuangtai);
printf(" info=%s ",neicun[i].info);
flag=1;
}
}
if(!flag)
printf("\n当前没有运行进程!\n");
}

4.1.3进程的换出

//进程换出
void huanchu(){
if(!shumu){
printf("当前没有运行进程!\n");
return;
}
printf("\n请输入换出进程的ID值");
scanf("%d",&pid);
for(int i=0;i<20;i++){
//定位,找到要换出的进程,根据其状态进行相应处理
if(pid==neicun[i].pid) {
if(neicun[i].zhuangtai==1){
neicun[i].zhuangtai==2;
guaqi++;
printf("\n已经成功换出进程\n");
}
else if(neicun[i].zhuangtai==0) printf("\n要换出的进程不存在\n");
else printf("\n要换出的进程已被挂起\n");
flag=1;
break;
}
}
//找不到,则说明进程不存在
if(flag==0) printf("\n要换出的进程不存在\n");
}

4.1.4进程的结束(杀死)

 1 //结束(杀死)进程
2 void kill(){
3 if(!shumu){
4 printf("当前没有运行进程!\n");
5 return;
6 }
7 printf("\n输入杀死进程的ID值");
8 scanf("%d",&pid);
9 for(int i=0;i<20;i++){
10 //定位,找到所要杀死的进程,根据其状态做出相应处理
11 if(pid==neicun[i].pid){
12 neicun[i].zhuangtai = 0;
13 shumu--;
14 printf("\n已经成功杀死进程\n");
15 }
16 else if(neicun[i].zhuangtai==0) printf ("\n要杀死的进程不存在\n");
17 else printf("\n要杀死的进程已被挂起\n");
18 flag=1;
19 break;
20 }
21 //找不到,则说明进程不存在
22 if(!flag) printf("\n 要杀死的进程不存在\n");
23
24 }

4.1.5进程的唤醒

 1 //唤醒进程
2 void huanxing(){
3 if (!shumu) {
4 printf("当前没有运行进程\n");
5 return;
6 }
7 if(!guaqi){
8 printf("\n当前没有挂起进程\n");
9 return;
10 }
11 printf("\n输入进程pid:\n");
12 scanf ("%d",&pid);
13 for (int i=0; i<20;i++) {
14 //定位,找到所要杀死的进程,根据其状态做相应处理
15 if (pid==neicun[i].pid) {
16 flag=false;
17 if(neicun[i].zhuangtai==2){
18 neicun[i].zhuangtai=1;
19 guaqi--;
20 printf ("\n已经成功唤醒进程\n");
21 }
22 else if(neicun[i].zhuangtai==0) printf("\n要唤醒的进程不存在\n");
23 else printf("\n要唤醒的进程已被挂起\n");
24 break;
25 }
26 }
27 //找不到,则说明进程不存在
28 if(flag) printf("\n要唤醒的进程不存在\n");
29 }

4.1.6 mian()函数

 1 //主函数
2 int main()
3 {
4 int n = 1;
5 int num;
6 //一开始所有进程都不在内存中
7 for(int i=0;i<20;i++)
8 neicun[i].zhuangtai = 0;
9 while(n){
10 printf("\n******************************************");
11 printf("\n* 进程演示系统 *");
12 printf("\n******************************************");
13 printf("\n*1.创建新的进程 2.查看运行进程 *");
14 printf("\n*3.换出某个进程 4.杀死运行进程 *");
15 printf("\n*5.唤醒某个进程 6.退出系统 *");
16 printf("\n******************************************");
17 printf("\n请选择(1~6)\n");
18 scanf("%d",&num);
19 switch(num){
20 case 1: create();break;
21 case 2: run();break;
22 case 3: huanchu(); break;
23 case 4: kill();break;
24 case 5: huanxing(); break;
25 case 6: printf("已退出系统");exit(0);
26 default: printf("请检查输入数值是否在系统功能中1~6");n=0;
27 }
28 flag = 0;//恢复标记
29 }
30 return 0;
31 }


5.运行结果截图

(图1--初始运行状态界面)

(图2--选择功能1 创建新进程)

源程序一次性创建5个进程,内存容量为20。

(图3--依次输入创建进程的pid、优先级、大小、内容)

(图4--选择功能2 显示当前运行的进程)

(图5--换出进程  输入要换出的进程pid,换出后提示进程已换出)

(图6--杀死进程  输入要结束的进程pid,之后执行操作杀死此进程,再次查看运行进程时可以看到进程1已不在运行进程列)

(图7--唤醒进程  输入要唤醒的进程pid,之后该进程将被挂起)

(图8--退出系统  输入6,选择退出系统功,系统结束运行)


本文为课程实验记录,参考学校实验教材书籍,重在学习交流。

码字不易,走过路过点个赞吧(❁´◡`❁)

操作系统实验一:进程管理(含成功运行C语言源代码)的更多相关文章

  1. 操作系统(2)_进程管理_李善平ppt

    所有程序都有CPU和io这两部分,即使没有用户输入也有输出. CPU最好特别忙,io空闲无所谓. 程序/数据/状态 三个维度来看进程. 等待的资源可能是io资源或者通信资源(别的进程的答复). 一个进 ...

  2. Linux进程管理专题

    Linux进程管理 (1)进程的诞生介绍了如何表示进程?进程的生命周期.进程的创建等等? Linux支持多种调度器(deadline/realtime/cfs/idle),其中CFS调度器最常见.Li ...

  3. BUPT复试专题—进程管理(2014网研)

    题目描述 在操作系统中,进程管理是非常重要的工作.每个进程都有唯一的进程标识PID.每个进程都可以启动子进程,此时我们称该它本身是其子进程的父进程.除PID为0的进程之外,每个进程冇且只冇一个父进程. ...

  4. Linux快速入门教程-进程管理ipcs命令学习

    使用Linux系统必备的技能之一就是Linux进程管理,系统运行的过程正是无数进程在运行的过程.这些进程的运行需要占用系统的内存等资源,做好系统进程的管理,对于我们合理分配.使用系统资源有非常大的意义 ...

  5. 操作系统--进程管理(Processing management)

    一.进程的组成 进程通常由程序.数据和进程控制块(Process Control Block,PCB)组成. 二. 进程的状态以及状态切换 进程执行时的间断性决定了进程可能具有多种状态,最基本的三种状 ...

  6. 十天学会CS之操作系统——进程管理01

    进程管理01 进程的概念 进程是计算机中一个非常重要的概念,在整个计算机发展历史中,操作系统中程序运行机制的演变按顺序大致可以分为: 单道程序:通常是指每一次将一个或者一批程序(一个作业)从磁盘加载进 ...

  7. 服务器端配置nodejs环境(使用pm2进程管理运行)

    一.brew安装: 由于Mac没有装ubantu,所以不能用apt-get命令,在本地命令行下Mac安装homebrew替代:  https://brew.sh 二.新开命令窗口,登录root用户,安 ...

  8. Linux 操作系统(四)用户组管理&进程管理&任务调度

    以下实例均在Centos7下验证 Centos7 查看命令帮助 man xxx 用户组管理 useradd useradd user1 password user1 cat /etc/passwd # ...

  9. Linux操作系统(6):进程管理和服务管理

    进程的基本介绍 1)在 LINUX 中,每个执行的程序(代码)都称为一个进程.每一个进程都分配一个 ID 号. 2)每一个进程,都会对应一个父进程,而这个父进程可以复制多个子进程.例如 www 服务器 ...

随机推荐

  1. leetcode 1541. 平衡括号字符串的最少插入次数

    问题描述 给你一个括号字符串 s ,它只包含字符 '(' 和 ')' .一个括号字符串被称为平衡的当它满足: 任何左括号 '(' 必须对应两个连续的右括号 '))' . 左括号 '(' 必须在对应的连 ...

  2. 系统信号SIGHUP、SIGQUIT、SIGTERM、SIGINT的场景

    SIGHUP:hong up 挂断.本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联.登录Linux时 ...

  3. 【机器学习】HMM

    机器学习算法-HMM 目录 机器学习算法-HMM 1. 模型定义 2. 序列生成 3. 概率计算 3.1 前向计算 3.2 后向计算 4. 学习 4.1 求解 4.2 求解 4.3 求解 5. 预测 ...

  4. unity3d inputfield标签控制台打印object

    inputfield标签控制台打印object 这说明没有字符串给入 这是因为 inputfield下的text不能人为写入值,只能在game界面输入. 所以这个标签里的text做个默认值不好搞.

  5. nacos集群开箱搭建

    记录/朱季谦 nacos是一款易于构建云原生应用的动态服务发现.配置管理和服务管理平台,简单而言,它可以实现类似zookeeper做注册中心的功能,也就是可以在springcloud领域替代Eurek ...

  6. MySQL的MyISAM与InnoDB的索引方式

    在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式. MyISAM索引实现 MyISAM引擎使用B+Tr ...

  7. gin中的SecureJSON 防止 json 劫持

    使用 SecureJSON 防止 json 劫持.如果给定的结构是数组值或map,则默认预置 "while(1)," 到响应体. package main import ( &qu ...

  8. Spring中的单例模式

    Spring中的单例模式 单例模式的介绍 1.1 简介 ​ 保证整个应用中某个实例有且只有一个 1.2作用 保证一个类仅有一个实例,并且提供一个访问它的全局访问点. 单例模式的优点和缺点 单例模式的优 ...

  9. python利用正则表达式提取文本中特定内容

    正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式. re 模块使 Python ...

  10. lambda表达式的学习

    Lambda表达式 为什么使用lambda表达式 Lambda表达式可以简化我们的代码,使我们只需要关注主要的代码就可以. //测试用的实体类 public class Employee { priv ...