操作系统-进程管理实验(2)

实验二  进程管理

一、目的

本课题实验的目的是,加深对进程概念及进程管理各个部分内容的理解;熟悉进程管理中主要数据结构的设计及进程调度算法,进程控制机构,同步机构,通信机构的实施。

二、题目

进程管理

三、要求及提示

1、要求设置PCB,进程控制原语,进程调度算法,能描述进程调度中不同进程状态之间的转换,设计一个允许n个进程并发运行的进程管理模拟系统。该系统包括有简单的进程控制,同步及通信机构,其进程调度算法可任意选择。每个进程用一个PCB表示,其内容可根据具体情况设置。各进程之间应有一定的同步关系。系统在运行过程中能显示或打印各进程的状态及有关参数的变化情况,以便观察诸进程的运行过程及系统的管理过程。

2、编程实现。

3、工具:C语言或其它高级语言

4、实验时间:2学时

四、实验报告

1、写出进程管理的思想。

2、画出算法流程图和设置的数据结构。

3、写出调试程序出现的问题及解决的方法。

4、打印实验报告及程序清单。

5、报告给出测试的结果。

五、范例

支持多个进程并发运行的简单进程管理模拟系统。

1、问题描述

本系统的同步机构采用的是信号量上的P,V操作的机制;控制机构包括阻塞和唤醒操作;时间片中断处理程序处理模拟的时间片中断;进程调度程序负责为各进程分配处理机。系统中设计了3个并发进程。它们之间有如下同步关系:3个进程需要互斥使用临界资源s2,进程1和进程2又需互斥使用临界资源s1。本系统在运行过程中随机打印出各进程的状态变换过程,系统的调度过程及公共变量的变化情况。

 

2、算法

系统为进程设置了5种运行状态:e-执行态;r-高就绪态;t-低就绪态(执行进程因时间片到限而转入);w-等待态;c-完成态。各进程的初始状态均设置为r。系统分时执行各进程,并规定3个进程的执行概率均为33%。通过产生随机数x来模拟时间片。当进程process1访问随机数x时,若x ≥0.33;当进程process2访问x时,若x<0.33或x≥0.66;当进程process3访问x时,若x<0.66,分别认为各进程的执行时间片到限,产生“时间片中断”而转入低就绪态t。

进程调度算法采用剥夺式最高优先数法。各进程的优先数通过键盘输入予以静态设置。调度程序每次总是选择优先数最小(优先权最高)的就绪进程投入执行。先从r状态进程中选择,再从t状态进程中选择。当现行进程唤醒某个等待进程,且被唤醒进程的优先数小于现行进程时,则剥夺现行进程的执行权。

各进程在使用临界资源s1和s2时,通过调用信号量sem1和sem2上的P,V操作来实现同步,阻塞和唤醒操作负责完成从进程的执行态到等待态到就绪态的转换。

系统启动后,在完成必要的系统初始化后便执行进程调度程序。但执行进程因“时间片中断”,或被排斥使用临界资源,或唤醒某个等待资源时,立即进行进程调度。当3个进程都处于完成状态后,系统退出运行。

图1和图2分别示出了系统主控程序和进程调度程序的大致流程。

 

3 、数据结构

(1)每个进程有一个进程控制块PCB,内容包括:

id        进程控制数,id=0,1,2;       

status    进程状态,可为e,r,t,w,c;

priorty   进程优先数;

nexrtwr   等待链指针,只是在同一信号量上等待的下一个进程的标时数。


 图2 进程调度程序

(2)信号量semaphore,对于临界资源 s1和s2分别有sem1和sem2均为互斥信号量。内容包括:

value     信号量值,初值为1;

firstwr    等待链首指针,指示该信号量上等待的下一个进程标识数。

(3)现场保留区,用数组savearea[3][4]表示,即每一个进程都有一个大小为4个单元的保留区,用来保存被“中断”时的现场信息,如通用寄存器的内容和断点地址等。此外,系统中还用到下列主要全程变量:

exe      执行进程指针,其值为进程标识数;

i         用来模拟一个通用寄存器;

addr     用来模拟程序计数器;

s1,s2    两个公用变量,与来共享临界资源。

4.程序清单

#include<stdio.h>

#define TRUE 1
#define FALSE 0
#define MAXPRI 100
#define NIL -1


void init();
int find();
void block(int se);
void wakeup(int se);
void eexit(int n);

struct{
		int id;  //进程标志符
		char status;   //进程状态,可为e,r,t,w,c;
		int nextwr;
		int priority;
}pcb[3];

struct{
		int value;
		int firstwr;
      }sem[2];

char savearea[3][4],addr;
int i,s1,s2,seed,exe=NIL;

void init()   /*initialization*/
{   
	int j;
    for(j=0;j<3;j++)
	{
		pcb[j].id=j;
	    pcb[j].status='r';
	    pcb[j].nextwr=NIL;
	    printf("\n process%d priority?",j+1);
	    scanf("%d",&i);
	    pcb[j].priority=i;
	 }
	sem[0].value=1;	
	sem[0].firstwr=NIL;
	
	sem[1].value=1;
	sem[1].firstwr=NIL;
	
	for(i=1;i<3;i++)
		for(j=0;j<4;j++)
			savearea[i][j]='0';
}

float random()
{
	int m;

	if (seed<0)
		m=-seed;
	else
		m=seed;

	seed=(25173*seed+13849)%65536;
	return(m/(float)32767.0);
}
timeint(char ad)    /*time slice interrupt */
{
	float x;
    x=random();

	if((x<0.33)&&(exe==0))
		return(FALSE); 

    if((x<0.66)&&(exe==1))
		return(FALSE);

    if((x<1.0)&&(exe==2))
		return(FALSE);

    savearea[exe][0]=i;
    savearea[exe][1]=ad;
    pcb[exe].status='t';

    printf("Time silce interrupt'\nprocess%d enter into ready.\n",exe+1);
    exe=NIL;
    return(TRUE);    
}
  
int scheduler()
{
	int pd;
	if((pd=find())==NIL&&exe==NIL)
		return(NIL);   /*quit system*/
	if(pd!=NIL)
	{
		if(exe==NIL)
		{
			pcb[pd].status='e';
			exe=pd;
			printf("process%d is executing.\n",exe+1);
		}
		else if(pcb[pd].priority<pcb[exe].priority)
		{
			pcb[exe].status='r';
			printf("process%d enter into ready\n",exe+1);
			pcb[pd].status='e';
			exe=pd;
			printf("process%d is executing\n",exe+1);
		}
	}
	i=savearea[exe][0];
	addr=savearea[exe][1];
	return(exe);
}
int find()
{
	int j,pd=NIL,w=MAXPRI;
	for (j=0;j<3;j++)
		if(pcb[j].status=='r')
			if (pcb[j].priority<w)
			{
				w=pcb[j].priority;pd=j;
			}
	if (pd==NIL)
		for (j=0;j<3;j++)
			if(pcb[j].status=='t')
				if(pcb[j].priority<w)
				{
					w=pcb[j].priority;pd=j;
				}
	return (pd);
}
p(int se,char ad)
{ 
	if(--sem[se].value>=0) 
		return(FALSE);
	block(se);
	savearea[exe][0]=i;
	savearea[exe][1]=ad;
	exe=NIL;
	return(TRUE);
}
void block(int se)
{
	int w;
	printf("process%d is blocked\n",exe+1);
	pcb[exe].status='w';
	pcb[exe].nextwr=NIL;
	if((w=sem[se].firstwr)==NIL)
		sem[se].firstwr=exe;
	else
	{
		while(pcb[w].nextwr!=NIL)
		w=pcb[w].nextwr;
		pcb[w].nextwr=exe;
	}
}
v(int se,char ad)
{
	if(++sem[se].value>0)   return(FALSE);
	wakeup(se);
	savearea[exe][1]=ad;
	savearea[exe][0]=i;
	return (TRUE);    /* scheduler*/
}
void wakeup(int se)
{
	int w;
    w=sem[se].firstwr;
    if(w!=NIL)
	{
		sem[se].firstwr=pcb[w].nextwr;
	    pcb[w].status='r';
	    printf("process%d is waken up\n",w+1);
	}
}
void process1()
{
	if(addr=='a')goto a1;
    if(addr=='b')goto b1;
    if(addr=='c')goto c1;
    if(addr=='d')goto d1;
    if(addr=='e')goto e1;
    if(addr=='f')goto f1;
	for(i=1;i<6;i++) 
	{
		printf("process1  calls P on the semaphore 1\n");
	    if(p(0,'a'))  break;  /*  process 1 is blocked*/
	 a1:  
		printf("process1 is executing in the cretical section 1\n");
        if(timeint('b')) 
			break;
     b1:
		printf("s1=%d\n",++s1);
		printf("process1 calls V on semaphore1 and quit cretical section 1.\n");         
		if(v(0,'c')) 
			break;
     c1: 
		printf("process1 calls P on semaphore1 2.\n");
		if(p(1,'d')) 
			break;
     d1:   
		printf("process1 is executing cretical section 2.\n");
		if(timeint ('e')) 
			break;
     e1:  
		printf("s2=%d\n",++s2);
		printf("process1 calls V on semephore2 and quit cretical section2.\n");
		if(v(1,'f') )
			break;
     f1:   
		printf("process1 cycle count=%d\n",i);
	}
	if(i<6) return;
    eexit(0);
}
void process2()
{
     if(addr=='a')goto a2;
     if(addr=='b')goto b2;
     if(addr=='c')goto c2;
     if(addr=='d')goto d2;
     if(addr=='e')goto e2;
     if(addr=='f')goto f2;
for(i=1;i<6;++i)
{
     printf("process2 calls Pon semephore2\n");
     if(p(1,'a')) break;
a2:   printf("process2 is executing on the cretical section2\n");
      if(timeint('b'))  break;
b2:   printf("s2=%d\n",++s2);
      printf("process2 calls V on semephore2 and quit cretical section2.\n");
      if(v(1,'c')) break;
c2:   printf("process2 calls P on semaphore1.\n");
      if(p(0,'d')) break;
d2:   printf("process2 is executing cretical section1.\n");
      if(timeint('e')) break;
e2:   printf("s1=%d\n",++s1);
      printf("process2 calls V on semephore1 and quit cretical section1.\n");
      if(v(0,'f')) break;
f2:   printf("process2 cycle count=%d\n",i);
}
      if(i<6) return;
      eexit(1);
}
void process3()
{
     if(addr=='a')goto a3;
     if(addr=='b')goto b3;
     if(addr=='c')goto c3;
	for(i=1;i<6;++i)  
	{
       printf("process3 calls P on semaphore2\n");
       if(p(1,'a')) break;
a3:   printf("process3 is executing on the cretical section \n");
      if(timeint('b')) break;
b3:   printf("s2=%d\n",++s2);
      printf("process3 calls V on semaphore2 and quit cretical section.\n");
      if(v(1,'c')) break;
c3:   printf("process3 cycle count=%d\n");
	}
       if(i<6)  return;
       eexit(2);
}
void eexit(int n)
{
	pcb[n].status='c';
	printf("process%d is completed !\n",n+1);
	exe=NIL;
}

void main()
{
    int k;
    printf("****process management*******\n\n");
    init();
    printf("s1=%d,s2=%d\n",s1,s2);
    printf("process1,process2,process3 are all in ready1\n");
    for( ;  ;)
	{
		if((k=scheduler())!=NIL)
		{
			switch(k)
			{
				case 0:		process1();		break;
				case 1:		process2();		break;
				case 2:		process3();		break;
				default:	printf("process identifer error\n");	break;
			}
		}
		else 
			 break;
	}
    printf("s1=%d,s2=%d\n",s1,s2);
    printf("\n ******END*******\n");
}


  • 13
    点赞
  • 142
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实验 进程管理   Windows所创建的每个进程都从调用CreateProcess() API函数开始,该函数的任务是在对象管理器子系统内初始化进程对象。每一进程都以调用ExitProcess() 或TerminateProcess() API函数终止。通常应用程序的框架负责调用 ExitProcess() 函数。对于C++ 运行库来说,这一调用发生在应用程序的main() 函数返回之后。 1. 创建进程 CreateProcess() 调用的核心参数是可执行文件运行时的文件名及其命令行。表 2-1详细地列出了每个参数的类型和名称。   表2-1 CreateProcess() 函数的参数 参数名称 使用目的 LPCTSTR lpApplivationName 全部或部分地指明包括可执行代码的EXE文件的文件名 LPCTSTR lpCommandLine 向可执行文件发送的参数 LPSECURIITY_ATTRIBUTES lpProcessAttributes 返回进程句柄的安全属性。主要指明这一句柄是否应该由其他子进程所继承 LPSECURIITY_ATTRIBUTES lpThreadAttributes 返回进程的主线程的句柄的安全属性 BOOL bInheritHandle 一种标志,告诉系统允许新进程继承创建者进程的句柄 DWORD dwCreationFlage 特殊的创建标志 (如CREATE_SUSPENDED) 的位标记 LPVOID lpEnvironment 向新进程发送的一套环境变量;如为null值则发送调用者环境 LPCTSTR lpCurrentDirectory 新进程的启动目录 STARTUPINFO lpStartupInfo STARTUPINFO结构,包括新进程的输入和输出配置的详情 LPPROCESS_INFORMATION lpProcessInformation 调用的结果块;发送新应用程序的进程和主线程的句柄和ID   可以指定第一个参数,即应用程序的名称,其中包括相对于当前进程的当前目录的全路径或者利用搜索方法找到的路径;lpCommandLine参数允许调用者向新应用程序发送数据;接下来的三个参数与进程和它的主线程以及返回的指向该对象的句柄的安全性有关。 然后是标志参数,用以在dwCreationFlags参数中指明系统应该给予新进程什么行为。经常使用的标志是CREATE_SUSPNDED,告诉主线程立刻暂停。当准备好时,应该使用ResumeThread() API来启动进程。另一个常用的标志是CREATE_NEW_CONSOLE,告诉新进程启动自己的控制台窗口,而不是利用父窗口。这一参数还允许设置进程的优先级,用以向系统指明,相对于系统中所有其他的活动进程来说,给此进程多少CPU时间。 接着是CreateProcess() 函数调用所需要的三个通常使用缺省值的参数。第一个参数是lpEnvironment参数,指明为新进程提供的环境;第个参数是lpCurrentDirectory,可用于向主创进程发送与缺省目录不同的新进程使用的特殊的当前目录;第三个参数是STARTUPINFO数据结构所必需的,用于在必要时指明新应用程序的主窗口的外观。 CreateProcess() 的最后一个参数是用于新进程对象及其主线程的句柄和ID的返回值缓冲区。以PROCESS_INFORMATION结构中返回的句柄调用CloseHandle() API函数是重要的,因为如果不将这些句柄关闭的话,有可能危及主创进程终止之前的任何未释放的资源。 2. 正在运行的进程 如果一个进程拥有至少一个执行线程,则为正在系统中运行的进程。通常,这种进程使用主线程来指示它的存在。当主线程结束时,调用ExitProcess() API函数,通知系统终止它所拥有的所有正在运行、准备运行或正在挂起的其他线程。当进程正在运行时,可以查看它的许多特性,其中少数特性也允许加以修改。 首先可查看的进程特性是系统进程标识符 (PID) ,可利用GetCurrentProcessId() API函数来查看,与GetCurrentProcess() 相似,对该函数的调用不能失败,但返回的PID在整个系统中都可使用。其他的可显示当前进程信息的API函数还有GetStartupInfo()和GetProcessShutdownParameters() ,可给出进程存活期内的配置详情。 通常,一个进程需要它的运行期环境的信息。例如API函数GetModuleFileName() 和GetCommandLine() ,可以给出用在CreateProcess() 中的参数以启动应用程序。在创建应用程序时可使用的另一个
### 回答1: Linux实验进程管理主要涉及到进程的创建、终止、查看和管理等方面。在Linux系统中,进程操作系统中最基本的执行单元,它是程序在执行过程中的一个实例。通过进程管理,我们可以控制和管理系统中的各个进程,从而保证系统的稳定性和安全性。 在Linux系统中,我们可以使用命令行工具来进行进程管理。其中,常用的命令包括ps、kill、top、nice等。通过这些命令,我们可以查看系统中正在运行的进程、终止指定的进程、调整进程的优先级等。 此外,Linux系统还提供了一些图形化的进程管理工具,如System Monitor、htop等。这些工具可以更直观地显示系统中的进程信息,并提供更丰富的操作选项。 总之,进程管理是Linux系统中非常重要的一部分,它对于系统的稳定性和安全性具有重要的影响。掌握进程管理的基本原理和常用命令,可以帮助我们更好地管理和维护Linux系统。 ### 回答2: Linux实验进程管理主要涉及了进程的创建、运行、退出等基本操作。在Linux系统中,进程是系统资源调度的基本单位,也是程序运行的基本单位。因此,在Linux操作系统中,对于进程管理的实现显得十分重要。 在实验中,我们学习了如何通过编程的方式进行进程的创建。首先,我们需要使用fork()函数来创建新的进程。这个函数会在调用的进程内部生成一个子进程,子进程会与父进程共享代码、数据、文件等资源,并且这两个进程的运行是相对独立的。在子进程中可以使用exec()函数来加载新的程序,从而实现一个新的进程。在实验中,我们尝试了几种不同的fork()和exec()函数的组合方式,例如:子进程执行一个程序,子进程替换成另一个程序等。这些不同的方式可以更加灵活地控制进程的创建和运行。 其次,我们学习了如何使用信号来管理进程。在Linux系统中,信号是一种异步的通知机制,它可以在运行中的进程之间进行通信,例如进程的退出通知等。我们使用signal()函数来安装信号处理程序,这个处理程序会在特定的信号到来时执行。例如,我们尝试了在子进程中安装SIGINT信号处理程序,当在终端输入Ctrl+C时,子进程会捕获到这个信号并调用处理程序。 另外,我们学习了如何使用管道来进行进程间通信。在Linux系统中,管道是进程间通信的一种常用方式。我们使用pipe()函数来创建管道,然后使用fork()函数创建子进程和父进程,两个进程之间可以通过管道来传输数据。在实验中,我们使用管道来实现父进程向子进程发送数据的过程,这个过程需要通过write()函数写入数据到管道中,子进程可以通过read()函数来读取管道中的数据。 综上所述,实验进程管理是一个非常实用的实验,我们通过实验学习了进程的创建、运行、退出等基本操作,学会了如何使用信号和管道进行进程通信,掌握了进程管理中一些常用的技巧和方法,这些技能对于我们后续的Linux系统学习和工作都是非常有帮助的。 ### 回答3: Linux实验进程管理是计算机操作系统课程中的一项实验任务,主要涉及如何创建、管理和控制进程。本实验要求学生在Linux操作系统下使用命令行工具,通过编写和运行C程序来实现进程的创建和管理。 在Linux中,进程操作系统的基本单位,每个进程都拥有自己的资源和内存空间。管理进程的操作可以通过Linux系统内核提供的一系列命令和系统调用来完成。常用的进程管理命令包括ps、kill、top等,它们可以帮助用户查看进程列表、杀死进程或者查看进程的状态。 本实验要求使用C语言编写程序并通过命令行编译执行。首先要实现进程的创建,通过fork系统调用可以创建一个子进程。父进程调用fork会返回子进程的pid,而子进程返回0,可以通过判断返回值来确定当前程序是父进程还是子进程。子进程可以调用exec系统调用来执行其他程序,从而实现进程间的交互和通信。 在进程管理中,还需要对进程进行调度和控制。可以通过信号来控制进程的行为,kill命令可以向指定进程发送不同的信号,例如SIGTERM信号可以结束进程,SIGINT信号可以停止进程。另外还可以使用nice命令来调整进程的优先级,通过top命令可以查看进程的状态和占用的系统资源。 总的来说,Linux实验进程管理是一项非常重要的实验任务,通过学习和实践可以帮助学生更深入地理解进程管理的原理和技术,为以后的系统管理和开发打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值