实验2
#include"math.h"
#include"sched.h"
#include"pthread.h"
#include"stdio.h"
#include"stdlib.h"
#include"semaphore.h"
typedef struct
{ //实时任务描述
char task_id;
int call_num; //任务发生次数
int ci; //任务处理时间
int ti; //任务发生周期
int ci_left;
int ti_left; //record the reduction of ti \ci
int flag; //任务是否活跃,0否,2是
int arg; //参数
pthread_t th; //任务对应线程
}task;
void proc(int * args);
void * idle();
int select_proc();//int alg
int task_num=0;
int idle_num=0;
int alg; //所选算法,1 for EDF,2 for RMS int curr_proc=-1;
int demo_time=100; //演示时间
task * tasks;
pthread_mutex_t proc_wait[10]; //the biggest number of tasks pthread_mutex_t main_wait,idle_wait;
float sum=0;
pthread_t idle_proc;
int main(int argc,char ** argv)
{
pthread_mutex_init(&main_wait , NULL);
pthread_mutex_lock(&main_wait); //下次执行lock等待
pthread_mutex_init(&idle_wait , NULL);
pthread_mutex_lock(&idle_wait); //下次执行lock等待
printf("Please input number of real time task:\n");
// int c;
scanf("%d",&task_num); //任务数
tasks=(task *)malloc(task_num *sizeof(task));
// while((c=getchar())!='\n' && c!=EOF); //清屏int i;
for(i=0 ; i { pthread_mutex_init( &proc_wait[i] , NULL); pthread_mutex_lock( &proc_wait[i]); } for(i=0;i { printf("Pleased input task id,followed by Ci and Ti:\n"); getchar(); scanf("%c,%d,%d,",&tasks[i].task_id, &tasks[i].ci, &tasks[i].ti); tasks[i].ci_left=tasks[i].ci; tasks[i].ti_left=tasks[i].ti; tasks[i].flag=2; tasks[i].arg=i; tasks[i].call_num=1; sum=sum+(float)tasks[i].ci / (float)tasks[i].ti; // while((c=getchar())!='\n'&&c!=EOF); //清屏 } printf("Please input algorithm,1 for EDF,2 for RMS:"); getchar(); scanf("%d",&alg); printf("Please input demo time:"); scanf("%d", &demo_time); double r = 1; //EDF算法,最早截止期优先调度if(alg == 2) { //RMS算法,速率单调调度 r=((double)task_num)*(exp(log(2)/(double)task_num)-1); printf("r is %lf\n",r); } if(sum>r) // 综合EDF和RMS算法任务不可可调度的情况 { //不可调度 printf("(sum=%lf>r=%lf),not schedulable!\n",sum,r); exit(2); } //创建闲逛线程 pthread_create(&idle_proc , NULL , (void *)idle , NULL); for(i=0;i pthread_create(&tasks[i].th, NULL, (void*)proc, &tasks[i].arg); for(i=0;i { int j; if((curr_proc=select_proc(alg))!=-1) { //按调度算法选择线程 pthread_mutex_unlock(&proc_wait[curr_proc]); //唤醒 pthread_mutex_lock(&main_wait); //主线程等待} else { //无可运行任务,选择闲逛线程 pthread_mutex_unlock(&idle_wait); pthread_mutex_lock(&main_wait); } for(j=0;j { //Ti--,直至为0时开始下一周期 if(--tasks[j].ti_left==0) { tasks[j].ti_left=tasks[j].ti; tasks[j].ci_left=tasks[j].ci; pthread_create(&tasks[j].th,NULL,(void*)proc,&tasks[j].arg); tasks[j].flag=2; } } } printf("\n"); sleep(10); }; void proc(int *args) { while(tasks[*args].ci_left>0) { pthread_mutex_lock(&proc_wait[*args]); //等待被调度 if(idle_num!=0) { printf("idle(%d)",idle_num); idle_num=0; } printf("%c%d",tasks[*args].task_id,tasks[*args].call_num); tasks[*args].ci_left--; //执行一个时间单位 if(tasks[*args].ci_left==0) { printf("(%d)",tasks[*args].ci); tasks[*args].flag=0; tasks[*args].call_num++; // } pthread_mutex_unlock(&main_wait); //唤醒主线程} }; void *idle() { while(1) { pthread_mutex_lock(&idle_wait); //等待被调度 printf("->"); //空耗一个时间单位 idle_num++; pthread_mutex_unlock(&main_wait); //唤醒主线程} }; int select_proc(int alg) { int j; int temp1,temp2; temp1=10000; temp2=-1; if((alg==2)&&(curr_proc!=-1)&&(tasks[curr_proc].flag!=0)) return curr_proc; for(j=0;j { if(tasks[j].flag==2) { switch(alg) { case 1: //EDF算法 if(temp1>tasks[j].ci_left) { temp1=tasks[j].ci_left; temp2=j; } case 2: //RMS算法 if(temp1>tasks[j].ti) { temp1=tasks[j].ti; temp2=j; } } } } return temp2; //return the selected thread or task number }; 实验三 #ifdef HAVE_CONFIG_H #include #endif #include #include #define MAPSIZE 100 struct map { int m_addr; int m_size; }; struct map map[MAPSIZE]; int BF_malloc(struct map*mp, int size) { register int a,s; register struct map*bp,*bpp; for(bp=mp;bp->m_size;bp++) { if(bp->m_size >= size) { a=bp->m_addr; s=bp->m_size; for(bpp=bp;bpp->m_size;bpp++) { if(bpp->m_size >= size && bpp->m_size < s) { a=bpp->m_addr; s=bpp->m_size; //a bp=bpp; } } bp->m_addr + = size; if((bp->m_size -= size) == 0) { do { bp++; (bp-1)->m_addr = bp->m_addr; } while((bp-1)->m_size=bp->m_size); } return(a); } } return(-1); } int WF_malloc(struct map*mp,int size) { register int a,s; register struct map*bp, *bpp; for(bp=mp;bp->m_size;bp++) { if(bp->m_size >=size) { a=bp->m_addr; s=bp->m_size; for(bpp=bp;bpp->m_size;bpp++) { if(bpp->m_size > s) { a=bpp->m_addr; s=bpp->m_size; bp=bpp; } } bp->m_addr += size; if((bp->m_size -= size)==0) { do { bp++; (bp-1)->m_addr=bp->m_addr; } while((bp-1)->m_size=bp->m_size); } return(a); } } return(-1); } void mfree(struct map*mp ,int aa,int size) { register struct map*bp; register int t; register int a; a=aa; for(bp=mp; bp->m_addr<=a && bp->m_size!=0 ;bp++); if(bp>mp && (bp-1)->m_addr+(bp-1)->m_size==a) {//与前合并 (bp-1)->m_size += size; if(a+size == bp->m_addr) { (bp-1)->m_size += bp->m_size; while(bp->m_size) { bp++; (bp-1)->m_addr += bp->m_addr; (bp-1)->m_size += bp->m_size; }//前后合并 } } else { if(a+size ==bp->m_addr && bp->m_size) { bp->m_addr -=size; bp->m_size +=size; }//与后合并 else if(size) { do {//无合并 t=bp->m_addr; bp->m_addr=a; a=t; t=bp->m_size; bp->m_size=size; bp++; } while(size=t); } } } void init() { struct map *bp; int addr,size; int i=0; bp=map; printf("Please input starting addr and size:"); scanf("%d,%d",&addr,&size); bp->m_addr=addr; bp->m_size=size; (++bp)->m_size=0; getchar();// 消除回车换行 } void show_map() { int i=0; system("clear");// struct map *bp; bp=map; printf("\nCurrent memory map...\n"); printf("Address\t\tSize\n"); while(bp->m_size != 0) { //if() printf("<%d\t\t%d> \n",bp->m_addr,bp->m_size); bp++; } printf("\n"); } main() { int a,s; int c; int i; init(); printf("Please input ,b for BF, w for WF:"); scanf("%c",&c); do { show_map(); printf("Please input ,1 for request, 2 for release, 0 for exit:"); scanf("%d",&i); getchar(); //消除回车换行,否则影响下次输入 switch(i) { case 1: printf("please input size:"); scanf("%d",&s); if(c=='b') a=BF_malloc(map,s); else a=WF_malloc(map,s); if(a== -1) printf("request can't be satisfied\n"); else printf("alloc memory at address :%d,size:%d\n",a,s); break; case 2: printf("Please input addr and size:"); scanf("%d,%d",&a,&s); mfree(map,a,s); break; case 0: exit(0); } } while(1); } 实验四 //hashfile.c #include #include #include #include #include #include #include #include"HashFile.h" int hashfile_creat(const char *filename,mode_t mode,int reclen,int total_rec_num) { struct HashFileHeader hfh; int fd; int rtn; char *buf; int i=0; hfh.sig = 31415926; hfh.reclen = reclen; hfh.total_rec_num = total_rec_num; hfh.current_rec_num = 0; //fd = open(filename,mode); fd = creat(filename,mode); if(fd != -1) { rtn = write(fd,&hfh,sizeof(struct HashFileHeader)); //lseek(fd,sizeof(struct HashFileHeader),SEEK_SET); if(rtn != -1) { buf = (char*)malloc((reclen+sizeof(struct CFTag))*total_rec_num); memset(buf,0,(reclen+sizeof(struct CFTag))*total_rec_num); ////???? rtn = write(fd,buf,(reclen+sizeof(struct CFTag))*total_rec_num); free(buf); } close(fd); return rtn; } else { close(fd); return -1; } } int hashfile_open(const char *filename,int flags,mode_t mode) { int fd = open(filename,flags,mode); struct HashFileHeader hfh; if(read(fd,&hfh,sizeof(struct HashFileHeader))!= -1) { lseek(fd,0,SEEK_SET); if(hfh.sig == 31415926) return fd; else return -1; } else return -1; } int hashfile_close(int fd) { return close(fd); } int hashfile_read(int fd,int keyoffset,int keylen,void *buf) { struct HashFileHeader hfh; readHashFileHeader(fd,&hfh); int offset = hashfile_findrec(fd,keyoffset,keylen,buf); if(offset != -1) { lseek(fd,offset+sizeof(struct CFTag),SEEK_SET); return read(fd,buf,hfh.reclen); } else { return -1; } } int hashfile_write(int fd,int keyoffset,int keylen,void *buf) { return hashfile_saverec(fd,keyoffset,keylen,buf); //return -1; } int hashfile_delrec(int fd,int keyoffset,int keylen,void *buf) { int offset; offset = hashfile_findrec(fd,keyoffset,keylen,buf); if(offset != -1) { struct CFTag tag; read(fd,&tag,sizeof(struct CFTag)); tag.free =0; //置空闲标志 lseek(fd,offset,SEEK_SET); write(fd,&tag,sizeof(struct CFTag)); struct HashFileHeader hfh; readHashFileHeader(fd,&hfh); int addr = hash(keyoffset,keylen,buf,hfh.total_rec_num); offset = sizeof(struct HashFileHeader)+addr*(hfh.reclen+sizeof(struct CFTag)); if(lseek(fd,offset,SEEK_SET)==-1) return -1; read(fd,&tag,sizeof(struct CFTag)); tag.collision--; //冲突计数减1 lseek(fd,offset,SEEK_SET); write(fd,&tag,sizeof(struct CFTag)); hfh.current_rec_num--; //当前记录数减1 lseek(fd,0,SEEK_SET); write(fd,&hfh,sizeof(struct HashFileHeader)); } else { return -1; } } int hashfile_findrec(int fd,int keyoffset,int keylen,void *buf) { struct HashFileHeader hfh; readHashFileHeader(fd,&hfh); int addr = hash(keyoffset,keylen,buf,hfh.total_rec_num); int offset = sizeof(struct HashFileHeader)+addr*(hfh.reclen+sizeof(struct CFTag)); if(lseek(fd,offset,SEEK_SET)==-1) return -1; struct CFTag tag; read(fd,&tag,sizeof(struct CFTag)); char count = tag.collision; if(count==0) return -1; //不存在 recfree: if(tag.free == 0) { offset += hfh.reclen+sizeof(struct CFTag); if(lseek(fd,offset,SEEK_SET)==-1) return -1; read(fd,&tag,sizeof(struct CFTag)); goto recfree; } else { char *p =(char*)malloc(hfh.reclen*sizeof(char)); read(fd,p,hfh.reclen); //printf("Record is {%d , %s}\n",((struct jtRecord *)p)->key,((struct jtRecord *p)->other); char *p1,*p2; p1 = (char *)buf+keyoffset; p2 = p + keyoffset; int j=0; while((*p1 == *p2)&&(j { p1++; p2++; j++; } if(j==keylen) { free(p); p = NULL; return(offset); } else { if(addr == hash(keyoffset,keylen,p,hfh.total_rec_num)) { count--; if(count == 0) { free(p); p = NULL; return -1;//不存在 } } free(p); p = NULL; offset += hfh.reclen+sizeof(struct CFTag); if(lseek(fd,offset,SEEK_SET) == -1) return -1; read(fd,&tag,sizeof(struct CFTag)); goto recfree; } } } int hashfile_saverec(int fd,int keyoffset,int keylen,void *buf) { if(checkHashFileFull(fd)) { return -1; } struct HashFileHeader hfh; readHashFileHeader(fd,&hfh); int addr = hash(keyoffset,keylen,buf,hfh.total_rec_num); int offset = sizeof(struct HashFileHeader)+addr*(hfh.reclen+sizeof(struct CFTag)); if(lseek(fd,offset,SEEK_SET)==-1) return -1; struct CFTag tag; read(fd,&tag,sizeof(struct CFTag)); tag.collision++; lseek(fd,sizeof(struct CFTag)*(-1),SEEK_CUR); write(fd,&tag,sizeof(struct CFTag)); while(tag.free!=0) //冲突,顺序探查 { offset += hfh.reclen+sizeof(struct CFTag); if(offset >= lseek(fd,0,SEEK_END)) offset = sizeof(struct HashFileHeader); //reach at and,then rewind if(lseek(fd,offset,SEEK_SET)==-1) return -1; read(fd,&tag,sizeof(struct CFTag)); } tag.free =-1; lseek(fd,sizeof(struct CFTag)*(-1),SEEK_CUR); write(fd,&tag,sizeof(struct CFTag)); write(fd,buf,hfh.reclen); hfh.current_rec_num++; lseek(fd,0,SEEK_SET); return write(fd,&hfh,sizeof(struct HashFileHeader)); //存入记录 } int hash(int keyoffset,int keylen,void *buf,int total_rec_num) { int i=0; char *p =(char*)buf+keyoffset; int addr =0; for(i=0;i { addr += (int)(*p); p++; } return addr%(int)(total_rec_num*COLLISIONFACTOR); } int checkHashFileFull(int fd) { struct HashFileHeader hfh; readHashFileHeader(fd,&hfh); if(hfh.current_rec_num return 0; else return 1; } int readHashFileHeader(int fd,struct HashFileHeader *hfh) { lseek(fd,0,SEEK_SET); return read(fd,hfh,sizeof(struct HashFileHeader)); } //hashfile.h #include #include #define COLLISIONFACTOR 0.5 struct HashFileHeader { int sig; //Hash文件印鉴 int reclen; //记录长度 int total_rec_num; //总记录数 int current_rec_num; //当前记录数 }; struct CFTag { char collision; //冲突计数 char free; //空闲标志 }; int hashfile_creat(const char *filename,mode_t mode,int reclen,int total_rec_num); //int hashfile_open(const char *filename,int flags); int hashfile_open(const char *filename,int flags,mode_t mode); int hashfile_close(int fd); int hashfile_read(int fd,int keyoffset,int keylen,void *buf); int hashfile_write(int fd,int keyoffset,int keylen,void *buf); int hashfile_delrec(int fd,int keyoffset,int keylen,void *buf); int hashfile_findrec(int fd,int keyoffset,int keylen,void *buf); int hashfile_saverec(int fd,int keyoffset,int keylen,void *buf); int hash(int keyoffset,int keylen,void *buf,int total_rec_num); int checkHashFileFull(int fd); int readHashFileHeader(int fd,struct HashFileHeader *hfh); //jtRecord.c #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include"HashFile.h" #include"jtRecord.h" #define KEYOFFSET 0 #define KEYLEN sizeof(int) #define FileNAME "jing.hash" void showHashFile(); int main(int argc,char *argv[]) { struct jtRecord rec[6] = {{1,"jing"},{2,"wang"},{3,"li"},{4,"zhang"},{5,"qing"},{6,"yuan"}}; int j=0; for(j=0;j<6;j++) { printf("<%d,%d> \t",rec[j].key,hash(KEYOFFSET,KEYLEN,&rec[j],6)); } int fd = hashfile_creat(FileNAME,O_RDWR|O_CREAT,RECORDLEN,6); int i=0; printf("\nOpen and Save Record...\n"); fd = hashfile_open(FileNAME,O_RDWR,0); for(i=0;i<6;i++) { hashfile_saverec(fd,KEYOFFSET,KEYLEN,&rec[i]); } hashfile_close(fd); showHashFile(); //Demo find Rec printf("\nFind Record..."); fd = hashfile_open(FileNAME,O_RDWR,0); int offset = hashfile_findrec(fd,KEYOFFSET,KEYLEN,&rec[4]); printf("\noffset is %d\n",offset); hashfile_close(fd); struct jtRecord jt; struct CFTag tag; fd = open(FileNAME,O_RDWR); lseek(fd,offset,SEEK_SET); read(fd,&tag,sizeof(struct CFTag)); printf("Tag is <%d,%d> \t",tag.collision,tag.free); read(fd,&jt,sizeof(struct jtRecord)); printf("Record is {%d,%s} \n",jt.key,jt.other); //Demo Delete Rec printf("\nDelete Record..."); fd = hashfile_open(FileNAME,O_RDWR,0); hashfile_delrec(fd,KEYOFFSET,KEYLEN,&rec[2]); hashfile_close(fd); showHashFile(); //Demo Read fd = hashfile_open(FileNAME,O_RDWR,0); char buf[32]; memcpy(buf,&rec[1],KEYLEN); hashfile_read(fd,KEYOFFSET,KEYLEN,buf); printf("\nRead Record is {%d,%s} \n",((struct jtRecord *)buf)->key,((struct jtRecord *)buf)->other); hashfile_close(fd); //Demo Write printf("\n Write Record..."); fd = hashfile_open(FileNAME,O_RDWR,0); hashfile_write(fd,KEYOFFSET,KEYLEN,&rec[3]); hashfile_close(fd); showHashFile(); return 0; } void showHashFile() { int fd; printf("\n"); fd = open(FileNAME,O_RDWR); lseek(fd,sizeof(struct HashFileHeader),SEEK_SET); struct jtRecord jt; struct CFTag tag; while(1) { if(read(fd,&tag,sizeof(struct CFTag))<=0) break; printf("Tag is <%d,%d>\t",tag.collision,tag.free); if(read(fd,&jt,sizeof(struct jtRecord))<=0) break; printf("Record is {%d,%s}\n",jt.key,jt.other); } close(fd); } //jtRecord.h #define RECORDLEN 32 struct jtRecord { int key; char other[RECORDLEN-sizeof(int)]; }; #ifdef HAVE_CONFIG_H #include #endif 实验六 #include #include #include #include #include uniom semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }arg; int semid; philosopher(int i) { struct sembuf sbuf[2]; sbuf[0].sem_num=i; sbuf[0].sem_flg=SEM_UNDO; sbuf[1].sem_num=(i+1)%5; sbuf[1].sem_flg=SEM_UNDO; while(1) { printf(" philosopher %d is thingking\n",i); sleep(2); printf(" philosopher %d is hungry\n",i); sbuf[0].sem_op=-1; sbuf[1].sem_op=-1; semop(semid,sbuf,2); printf(" philosopher %d is eating\n",i); sleep(2); sbuf[0].sem_op=1; sbuf[1].sem_op=1; semop(semid,sbuf,2); } } main() { int semid,key,pid,status,i; key=ftok("fname",1); semid=semget(key,5,IPC_CREAT|0666); arg.val=1; for(i=0;i<5;i++) semctl(semid,i,SETVAL,arg); for(i=0;i<5;i++) { pid=fork(); if(pid==0) philosopher(i); } pid=wait(&status); } 实验七 #include #include #include #include #include #include struct megbuf { long mtype; char mtext[1024]; }mgb; main() { key_t key; int p1,p2,p3,p4; key=ftok(IPC_PRIVATE,1); msgid=msgget(key,IPC_CREAT|0666); if(msgid<0) { perror(" message queue creation error\n"); exit(0); } p1=fork(); if(p1==0) { char a[64][64]; for(i=0;i<64;i++) { for(j=0;j<64;j++) { if(i<32&&j<32) a[i,j]='a'; if(i<32&&j>=32) a[i,j]='b'; if(i>=32&&j<32) a[i,j]='c'; 计算机操作系统实验报告 实验内容: P、V原语的模拟实现 实验类型:验证型 指导教师:毕国堂 专业班级: 姓名: 学号: 实验地点:东6E507 实验时间:2017/10/23 一、实验目的 1.理解信号量相关理论 2.掌握记录型信号量结构 3.掌握P、V原语实现机制 二、实验内容 1.输入给定的代码 2.进行功能测试并得出证正确结果 三、实验要求 1.分析signal和wait函数功能模块 ●Signal函数 在进行资源增加时,首先判断增加的资源是否存在,如果不存在则报错 并结束函数;如果存在则将需要增加的资源数量加一,然后再判断增加 后的资源数是否大于0,如果大于0则表示之前等待队列为空,没有需 要分配的进程;如果增加后的资源不大于0,表示之前等待队列中存在 进程,则将队首的进程取出并将资源分给该进程。 ●Wait 函数 在执行wait函数时,先判断请求的资源和进程是否存在,如果不存在则 报错提示;如果存在则将对应资源的资源数减一,然后判断减少后的资 源数是否小于0,如果小于0,表示该资源等待队列为空,可直接将资源 分配给请求的进程;如果不小于0则表示之前资源的等待队列不为空, 则将请求的进程插在等待队列最后。 2.画出signal和wait函数流程图 3.撰写实验报告 四、实验设备 1.PC机1台安装visual c++ 6.0 五、测试 1.首先将所有的资源分配完 2.这时再请求资源时就会出现等待现象 3.此时增加一个资源s0,则进程1对s0的等待结束直接获取资源s0 4.当再增加资源s0、s1时则进程1也结束对资源s1的等待,并且s0资源 为有空闲状态 六、实验思考 1.如何修改wait操作,使之能一次申请多个信号量? wait函数传入一个进程号和多个资源名,在wait函数中使用循环依 // tjty.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include block[i].timer = 0; } page = new pageInfor[Psize]; for(i=0; i #include 一、实验目的 通过对进程调度算法的设计,深入理解进程调度的原理。 进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。 进程调度分配处理机,是控制协调进程对CPU的竞争,即按一定的调度算法从就绪队列中选中一个进程,把CPU的使用权交给被选中的进程。 进程通过定义一个进程控制块的数据结构(PCB)来表示;每个进程需要赋予进程ID、进程到达时间、进程需要运行的总时间的属性;在RR中,以1为时间片单位;运行时,输入若干个进程序列,按照时间片输出其执行序列。 二、实验环境 VC++6.0 三、实验内容 实现短进程优先调度算法(SPF)和时间片轮转调度算法(RR) [提示]: (1) 先来先服务(FCFS)调度算法 原理:每次调度是从就绪队列中,选择一个最先进入就绪队列的进程,把处理器分配给该进程,使之得到执行。该进程一旦占有了处理器,它就一直运行下去,直到该进程完成或因发生事件而阻塞,才退出处理器。 将用户作业和就绪进程按提交顺序或变为就绪状态的先后排成队列,并按照先来先服务的方式进行调度处理,是一种最普遍和最简单的方法。它优先考虑在系统中等待时间最长的作业,而不管要求运行时间的长短。 按照就绪进程进入就绪队列的先后次序进行调度,简单易实现,利于长进程,CPU繁忙型作业,不利于短进程,排队时间相对过长。 (2) 时间片轮转调度算法RR 原理:时间片轮转法主要用于进程调度。采用此算法的系统,其程序就绪队列往往按进程到达的时间来排序。进程调度按一定时间片(q)轮番运行各个进程. 进程按到达时间在就绪队列中排队,调度程序每次把CPU分配给就绪队列首进程使用一个时间片,运行完一个时间片释放CPU,排到就绪队列末尾参加下一轮调度,CPU分配给就绪队列的首进程。 固定时间片轮转法: 1 所有就绪进程按 FCFS 规则排队。 2 处理机总是分配给就绪队列的队首进程。 3 如果运行的进程用完时间片,则系统就把该进程送回就绪队列的队尾,重新排队。 4 因等待某事件而阻塞的进程送到阻塞队列。 5 系统把被唤醒的进程送到就绪队列的队尾。 可变时间片轮转法: 1 进程状态的转换方法同固定时间片轮转法。 2 响应时间固定,时间片的长短依据进程数量的多少由T = N × ( q + t )给出的关系调整。 3 根据进程优先级的高低进一步调整时间片,优先级越高的进程,分配的时间片越长。 多就绪队列轮转法: (3) 算法类型 (4)模拟程序可由两部分组成,先来先服务(FCFS)调度算法,时间片轮转。流程图如下: 广州大学学生实验报告 1、实验目的 1.1、掌握进程的概念,明确进程的含义 1.2、认识并了解并发执行的实质 2.1、掌握进程另外的创建方法 2.2、熟悉进程的睡眠、同步、撤消等进程控制方法 3.1、进一步认识并发执行的实质 3.2、分析进程竞争资源的现象,学习解决进程互斥的方法 4.1、了解守护进程 5.1、了解什么是信号 5.2、INUX系统中进程之间软中断通信的基本原理 6.1、了解什么是管道 6.2、熟悉UNIX/LINUX支持的管道通信方式 7.1、了解什么是消息 7.2、熟悉消息传送的机理 8.1、了解和熟悉共享存储机制 二、实验内容 1.1、编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统 中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。试观察记录屏幕上的显示结果,并分析原因。 1.2、修改上述程序,每一个进程循环显示一句话。子进程显示'daughter …'及 'son ……',父进程显示'parent ……',观察结果,分析原因。 2.1、用fork( )创建一个进程,再调用exec( )用新的程序替换该子进程的内容 2.2、利用wait( )来控制进程执行顺序 3.1、修改实验(一)中的程序2,用lockf( )来给每一个进程加锁,以实现进程之间的互斥 3.2、观察并分析出现的现象 4.1、写一个使用守护进程(daemon)的程序,来实现: 创建一个日志文件/var/log/Mydaemon.log ; 每分钟都向其中写入一个时间戳(使用time_t的格式) ; 5.1、用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止: Child process1 is killed by parent! Child process2 is killed by parent! 父进程等待两个子进程终止后,输出如下的信息后终止: Parent process is killed! 5.2、用软中断通信实现进程同步的机理 重庆大学 学生实验报告 实验课程名称操作系统原理 开课实验室DS1501 学院软件学院年级2013专业班软件工程2 班学生姓名胡其友学号20131802 开课时间2015至2016学年第一学期 总成绩 教师签名洪明坚 软件学院制 《操作系统原理》实验报告 开课实验室:年月日学院软件学院年级、专业、班2013级软件工 程2班 姓名胡其友成绩 课程名称操作系统原理 实验项目 名称 指导教师洪明坚 教师 评语教师签名:洪明坚年月日 1.实验目的: ?进入实验环境 –双击expenv/setvars.bat ?检出(checkout)EPOS的源代码 –svn checkout https://www.wendangku.net/doc/7f2394701.html,/svn/epos ?编译及运行 –cd epos/app –make run ?清除所有的临时文件 –make clean ?调试 –make debug ?在“Bochs Enhanced Debugger”中,输入“quit”退出调试 –调试指令,请看附录A 2.实验内容: ?编写系统调用“time_t time(time_t *loc)” –功能描述 ?返回从格林尼治时间1970年1月1日午夜起所经过的秒数。如果指针loc 非NULL,则返回值也被填到loc所指向的内存位置 –数据类型time_t其实就是long ?typedef long time_t; 3.实验步骤: ?Kernel space –K1、在machdep.c中,编写系统调用的实现函数“time_t sys_time()”,计算用户秒数。需要用到 ?变量g_startup_time,它记录了EPOS启动时,距离格林尼治时间1970年1午夜的秒数 ?变量g_timer_ticks 上海电力学院 计算机操作系统原理 实验报告 题目:动态链接库的建立与调用 院系:计算机科学与技术学院 专业年级:信息安全2010级 学生姓名:李鑫学号:20103277 同组姓名:无 2012年11 月28 日上海电力学院 实验报告 课程名称计算机操作系统原理实验项目线程的同步 姓名李鑫学号20103277 班级2010251班专业信息安全 同组人姓名无指导教师姓名徐曼实验日期2012/11/28 实验目的和要求: (l)了解Windows内存管理机制,理解页式存储管理技术。 (2)熟悉Windows内存管理基本数据结构。 (3)掌握Windows内存管理基本API的使用。 实验原理与内容 使用Windows系统提供的函数和数据结构显示系统存储空间的使用情况,当内存和虚拟存储空间变化时,观察系统显示变化情况。 实验平台与要求 能正确使用系统函数GlobalMemoryStatus()和数据结构MEMORYSTATUS了解系统内存和虚拟空间使用情况,会使用VirtualAlloc()函数和VirtualFree()函数分配和释放虚拟存储空间。 操作系统:Windows 2000或Windows XP 实验平台:Visual Studio C++ 6.0 实验步骤与记录 1、启动安装好的Visual C++ 6.0。 2、选择File->New,新建Win32 Console Application程序, 由于内存分配、释放及系统存储 空间使用情况均是Microsoft Windows操作系统的系统调用,因此选择An application that support MFC。单击确定按钮,完成本次创建。 3、创建一个支持MFC的工程,单击完成。 学生学号 实验课成绩 武汉理工大学 学生实验报告书 实验课程名称 计算机操作系统 开 课 学 院 计算机科学与技术学院 指导老师姓名 学 生 姓 名 学生专业班级 2016 — 2017 学年第一学期 实验三 内存管理 一、设计目的、功能与要求 1、实验目的 掌握内存管理的相关内容,对内存的分配和回收有深入的理解。 2、实现功能 模拟实现内存管理机制 3、具体要求 任选一种计算机高级语言编程实现 选择一种内存管理方案:动态分区式、请求页式、段式、段页式等 能够输入给定的内存大小,进程的个数,每个进程所需内存空间的大小等 能够选择分配、回收操作 内购显示进程在内存的储存地址、大小等 显示每次完成内存分配或回收后内存空间的使用情况 二、问题描述 所谓分区,是把内存分为一些大小相等或不等的分区,除操作系统占用一个分区外,其余分区用来存放进程的程序和数据。本次实验中才用动态分区法,也就是在作业的处理过程中划分内存的区域,根据需要确定大小。 动态分区的分配算法:首先从可用表/自由链中找到一个足以容纳该作业的可用空白区,如果这个空白区比需求大,则将它分为两个部分,一部分成为已分配区,剩下部分仍为空白区。最后修改可用表或自由链,并回送一个所分配区的序号或该分区的起始地址。 最先适应法:按分区的起始地址的递增次序,从头查找,找到符合要求的第一个分区。 最佳适应法:按照分区大小的递增次序,查找,找到符合要求的第一个分区。 最坏适应法:按分区大小的递减次序,从头查找,找到符合要求的第一个分区。 三、数据结构及功能设计 1、数据结构 定义空闲分区结构体,用来保存内存中空闲分区的情况。其中size属性表示空闲分区的大小,start_addr表示空闲分区首地址,next指针指向下一个空闲分区。 //空闲分区 typedef struct Free_Block { int size; int start_addr; struct Free_Block *next; } Free_Block; Free_Block *free_block; 定义已分配的内存空间的结构体,用来保存已经被进程占用了内存空间的情况。其中pid作为该被分配分区的编号,用于在释放该内存空间时便于查找。size表示分区的大小,start_addr表示分区的起始地址,process_name存放进程名称,next指针指向下一个分区。 //已分配分区的结构体 typedef struct Allocate_Block { int pid; int size; int start_addr; char process_name[PROCESS_NAME_LEN]; struct Allocate_Block *next; } Allocate_Block; 2、模块说明 2.1 初始化模块 对内存空间进行初始化,初始情况内存空间为空,但是要设置内存的最大容量,该内存空间的首地址,以便之后新建进程的过程中使用。当空闲分区初始化 操作系统实验六磁盘调度算法正确C代码 文档编制序号:[KKIDT-LLE0828-LLETD298-POI08] 《操作系统》实验报告 【实验题目】:磁盘调度算法 【实验目的】 通过这次实验,加深对磁盘调度算法的理解,进一步掌握先来先服务FCFS,最短寻道时间优先SSTF,SCAN和循环SCAN算法的实现方法。【实验内容】 问题描述: 设计程序模拟先来先服务FCFS,最短寻道时间优先SSTF,SCAN和循环SCAN算法的工作过程。假设有n个磁道号所组成的磁道访问序列,给定开始磁道号m和磁头移动的方向(正向或者反向),分别利用不同的磁盘调度算法访问磁道序列,给出每一次访问的磁头移动距离,计算每种算法的平均寻道长度。 程序要求如下: 1)利用先来先服务FCFS,最短寻道时间优先SSTF,SCAN和循环SCAN算法模拟磁道访问过程。 2)模拟四种算法的磁道访问过程,给出每个磁道访问的磁头移动距离。 3)输入:磁道个数n和磁道访问序列,开始磁道号m和磁头移动方向(对SCAN和循环SCAN算法有效),算法选择1-FCFS,2-SSTF,3-SCAN,4-循环SCAN。 4)输出:每种算法的平均寻道长度。 实验要求: 1) 上机前认真复习磁盘调度算法,熟悉FCFS,SSTF,SCAN和循环SCAN算法的过程; 2) 上机时独立编程、调试程序; 3) 根据具体实验要求,完成好实验报告(包括实验的目的、内容、要求、源程序、实例运行结果截图)。 实验代码: #include 实验三进程与线程 问题: 进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位,具有动态性、并发性、独立性、异步性和交互性。然而程序是静态的,并且进程与程序的组成不同,进程=程序+数据+PCB,进程的存在是暂时的,程序的存在是永久的;一个程序可以对应多个进程,一个进程可以包含多个程序。当操作系统引入线程的概念后,进程是操作系统独立分配资源的单位,线程成为系统调度的单位,与同一个进程中的其他线程共享程序空间。 本次实验主要的目的是: (1)理解进程的独立空间; (2)加深对进程概念的理解,明确进程和程序的区别; (3)进一步认识并发执行的实质; (4)了解红帽子(Linux)系统中进程通信的基本原理。 (5)理解线程的相关概念。 要求: 1、请查阅资料,掌握进程的概念,同时掌握进程创建和构造的相关知识和线程创建和 构造的相关知识,了解C语言程序编写的相关知识; (1)进程: 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内 存;堆栈区域存储着活动过程调用的指令和本地变量。第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。 (2)进程的创建和构造: 进程简单来说就是在操作系统中运行的程序,它是操作系统资源管理的最小单位。但是进程是一个动态的实体,它是程序的一次执行过程。进程和程序的区别在于:进程是动态的,程序是静态的,进程是运行中的程序,而程序是一些保存在硬盘上的可执行代码。新的进程通过克隆旧的程序(当前进程)而建立。fork() 和clone()(对于线程)系统调用可用来建立新的进程。 (3)线程的创建和构造: 线程也称做轻量级进程。就像进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。但是,与独立的进程相比,进程中的线程之间的独立程度要小。它们共享内存、文件句柄和其他每个进程应有的状态。 线程的出现也并不是为了取代进程,而是对进程的功能作了扩展。进程可以支持多个线程,它们看似同时执行,但相互之间并不同步。一个进程中的多个线程共享相同的内存地址空间,这就意味着它们可以访问相同的变量和对象,而且它们从同一堆中分配对象。尽管这让线程之间共享信息变得更容易,但你必须小心,确保它们不会妨碍同一进程里的其他线程。 线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制,但与进程不同的是,同类的多个线程是共享同一块内存空间和一组系统资源的,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈。所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小得多,正因如此,线程也被称为轻型进程(light-weight process)。一个进程中可以包含多个线程。 2、理解进程的独立空间的实验内容及步骤 操作系统实验报告 集团企业公司编码:(LL3698-KKI1269-TM2483-LUI12689-ITT289- 实验二进程调度1.目的和要求 通过这次实验,理解进程调度的过程,进一步掌握进程状态的转变、进程调度的策略,进一步体会多道程序并发执行的特点,并分析具体的调度算法的特点,掌握对系统性能的评价方法。 2.实验内容 阅读教材《计算机操作系统》第二章和第三章,掌握进程管理及调度相关概念和原理。 编写程序模拟实现进程的轮转法调度过程,模拟程序只对PCB进行相应的调度模拟操作,不需要实际程序。假设初始状态为:有n个进程处于就绪状态,有m个进程处于阻塞状态。采用轮转法进程调度算法进行调度(调度过程中,假设处于执行状态的进程不会阻塞),且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。 程序要求如下: 1)输出系统中进程的调度次序; 2)计算CPU利用率。 3.实验环境 Windows操作系统、VC++6.0 C语言 4设计思想: (1)程序中进程可用PCB表示,其类型描述如下: structPCB_type { intpid;//进程名 intstate;//进程状态 2——表示“执行”状态 1——表示“就绪”状态 0——表示“阻塞”状态 intcpu_time;//运行需要的CPU时间(需运行的时间片个数) } 用PCB来模拟进程; (2)设置两个队列,将处于“就绪”状态的进程PCB挂在队列ready中;将处于“阻塞”状态的进程PCB挂在队列blocked中。队列类型描述如下: structQueueNode{ structPCB_typePCB; StructQueueNode*next; } 并设全程量: structQueueNode*ready_head=NULL,//ready队列队首指针 *ready_tail=NULL,//ready队列队尾指 针 实验二Linux 进程实验 姓名:段叶叶班级:信息1302 学号:07131052 地点:东区实验室FF109 时间:2014年10月13日星期一 成绩: 一、实验内容 1.创建进程的系统调用fork(); 2.创建进程的系统调用vfork(); 3.执行新程序的系统调用exec(); 4.等待进程结束的系统调用wait()或waitpid()。 前三题必做,最后一题选做。 二、实验目的 熟悉进程的系统调用。 三、实验环境 登陆Linux虚拟机,进入Linux shell,提示符为$,表示普通用户提示符。 四、实验题目 1. 【题目】:编写程序forkgrandchild.c,用来创建孙子进程。 【要求】:在读懂程序forktest.c的基础上,编写程序 forkgrandchild.c(forkgrandchild.c创建在用户名(如wm)目录下的process 目录下),所创建的程序forkgrandchild.c可实现创建孙子进程,并显示孙子进程的pid,其父进程的pid,forkgrandchild.c要求可读性好,用户界面友好。 【预备知识】: 1)Linux进程状态 ●运行状态:程序正在运行或在运行队列中等待运行。 ●可中断等待状态:进程正在等待某个事件完成,等待过程可被信号或定时器 唤醒。 ●不可中断等待状态:进程正在等待某个事件完成,不可被信号或定时器唤醒, 必须等待事件的发生,才可唤醒。 ●僵死状态:进程已终止,但进程描述符依然存在,直到父进程调动wait()函 数后释放。 ●停止状态:进程因收到SIGSTOP SIGSTP SIGTIN SIGTOU信号后停止运行 或该进程正在被跟踪(调式程序时)。 实验4 进程控制 1、实验目的 (1)通过对WindowsXP进行编程,来熟悉和了解系统。 (2)通过分析程序,来了解进程的创建、终止。 2、实验工具 (1)一台WindowsXP操作系统的计算机。 (2)计算机装有Microsoft Visual Studio C++6.0专业版或企业版。 3、预备知识 (3)·CreateProcess()调用:创建一个进程。 (4)·ExitProcess()调用:终止一个进程。 4、实验编程 (1)编程一利用CreateProcess()函数创建一个子进程并且装入画图程序(mspaint.exe)。阅读该程序,完成实验任务。源程序如下: # include < stdio.h > # include < windows.h > int main(VOID) ﹛STARTUPINFO si; PROCESS INFORMA TION pi; ZeroMemory(&si,sizeof(si)); Si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); if(!CreateProcess(NULL, “c: \ WINDOWS\system32\ mspaint.exe”, NULL, NULL, FALSE, 0, NULL, NULL, &si,&pi)) ﹛fprintf(stderr,”Creat Process Failed”); return—1; ﹜ WaitForSingleObject(pi.hProcess,INFINITE); Printf(“child Complete”); CloseHandle(pi.hProcess); CloseHandle(pi hThread); ﹜ 青岛理工大学课程实验报告 算法描述及实验步骤 功能:共享存储区的附接。从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。用于建立调用进程与由标识符shmid指定的共享内存对象之间的连接。 系统调用格式:virtaddr=shmat(shmid,addr,flag) 该函数使用头文件如下: #include 调 试 过 程 及 实 验 结 果 运行: 运行后: 总 结 (对实验结果进行分析,问题回答,实验心得体会及改进意见) 虽然对pipe()、msgget()、msgsnd()、msgrcv()、msgctl()、shmget()、shmat()、 shmdt()、shmctl()的功能和实现过程有所了解,但是运用还是不熟练,过去没 见过,所以运行了一个简单的程序。 利用管道机制、消息缓冲队列、共享存储区机制进行进程间的通信,加深了对 其了解。 (1)管道通信机制,同步的实现过程:当写进程把一定数量的数据写入pipe, 便去睡眠等待,直到读进程取走数据后,再把它唤醒。当读进程读一空pipe 时,也应睡眠等待,直到写进程将数据写入管道后,才将之唤醒,从而实现进 程的同步。 管道通信的特点:A管道是半双工的,数据只能向一个方向流动;需要双方通 信时,需要建立起两个管道;B. 只能用于父子进程或者兄弟进程之间(具有亲 缘关系的进程);C.单独构成一种独立的文件系统:管道对于管道两端的进程而 《操作系统》实验报告 实验序号: 4 实验项目名称:进程控制 Printf(“child Complete”); CloseHandle(pi.hProcess); CloseHandle(pi hThread); ﹜ 修改后: #include 实验任务:写出程序的运行结果。 4.正在运行的进程 (2)、编程二下面给出了一个使用进程和操作系统版本信息应用程序(文件名为4-5.cpp)。它利用进程信息查询的API函数GetProcessVersion()与GetVersionEx()的共同作用。确定运行进程的操作系统版本号。阅读该程序并完成实验任务。 #include 本科实验报告 课程名称:操作系统 学号: 姓名: 专业: 班级: 指导教师: 课内实验目录及成绩 信息技术学院 实验(实验一) 1 实验名称:基本shell命令及用户管理 2 实验目的 2.1 掌握安装Linux操作系统的方法。 2.2 掌握Linux操作系统的基本配置。 2.3 了解GNOME桌面环境。 2.4 掌握基本shell命令的使用。 3 实验准备 3.1 下载VMware Workstation虚拟机软件(版本不限)。 3.2 准备Linux操作系统的安装源(内核版本和发行版本均不限)。 注:实验准备、实验内容4.1和4.2作为回家作业布置,同学们利用课余时间可在私人计算机上完成。 4 实验要求、步骤及结果 4.1 安装虚拟机软件。 【操作要求】安装VMware Workstation虚拟机软件,并填写以下4.1.1和4.1.2的内容。 4.1.1【VMware Workstation虚拟机版本号】 4.1.2【主要配置参数】 4.2 安装Linux操作系统。 【操作要求】安装Linux操作系统,版本不限。 Linux发行版本: Linux内核版本: 【主要操作步骤:包括分区情况】 1、创建一台虚拟机安装操作系统时客户机操作系统选择Linux 2、修改虚拟机的安装路径。 3、建一个新的虚拟磁盘,磁盘的空间20GB,并且将单个文件存储虚拟磁盘。 4、设置分区完毕,安装虚拟机 4.3 了解Linux操作系统的桌面环境之一GNOME。 【操作要求】查看桌面图标,查看主菜单,查看个人用户主目录等个人使用环境。【操作步骤1】桌面图标 【操作步骤2】主菜单 【操作步骤3】个人用户主目录 【操作步骤4】启动字符终端 实验五:管道通信 实验内容: 1.阅读以下程序: #include 2.阅读以下程序: #include 操作系统试验指导 —. 课程的性质、目的和任务 操作系统在整个计算机系统软件中占有中心地位。其作用是对计算机系统进行统一的调度和管理,提供各种强有力的系统服务,为用户创造既灵活又方便的使用环境。本课程是计算机及应用专业的一门专业主干课和必修课。通过本课程的学习,使学生掌握操作系统的基本概念、设计原理及实施技术,具有分析操作系统和设计、实现、开发实际操作系统的能力。 二. 实验的意义和目的 操作系统是计算机专业学生的一门重要的专业课程。操作系统质量对整个计算机系统的性能和用户对计算机的使用有重大的影响。一个优良的操作系统能极大地扩充计算机系统的功能,充分发挥系统中各种设备的使用效率,提高系统工作的可靠性。由于操作系统涉及计算机系统中各种软硬件资源的管理,内容比较繁琐,具有很强的实践性。要学好这门课程,必须把理论与实践紧密结合,才能取得较好的学习效果。培养计算机专业的学生的系统程序设计能力,是操作系统课程的一个非常重要的环节。通过操作系统上机实验,可以培养学生程序设计的方法和技巧,提高学生编制清晰、合理、可读性好的系统程序的能力,加深对操作系统课程的理解。使学生更好地掌握操作系统的基本概念、基本原理、及基本功能,具有分析实际操作系统、设计、构造和开发现代操作系统的基本能力。 三.实验运行环境及上机前的准备 实验运行环境: C语言编程环境 上机前的准备工作包括: ●按实验指导书要求事先编好程序; ●准备好需要输入的中间数据; ●估计可能出现的问题; ●预计可能得到的运行结果。 四. 实验内容及安排 实验内容包括进程调度、银行家算法、页式地址重定位模拟,LRU算法模拟和先来先服务算法五个实验。每个实验介绍了实习的目的要求、内容和方法。 实验五线程的同步 1、实验目的 (1)进一步掌握Windows系统环境下线程的创建与撤销。 (2)熟悉Windows系统提供的线程同步API。 (3)使用Windows系统提供的线程同步API解决实际问题。 2、实验准备知识:相关API函数介绍 ①等待对象 等待对象(wait functions)函数包括等待一个对象(WaitForSingleObject ())和等待多个对象(WaitForMultipleObject())两个API函数。 1)等待一个对象 WaitForSingleObject()用于等待一个对象。它等待的对象可以为以下对象 之一。 ·Change ontification:变化通知。 ·Console input: 控制台输入。 ·Event:事件。 ·Job:作业。 ·Mutex:互斥信号量。 ·Process:进程。 ·Semaphore:计数信号量。 ·Thread:线程。 ·Waitable timer:定时器。 原型: DWORD WaitForSingleObject( HANDLE hHandle, // 对象句柄 DWORD dwMilliseconds // 等待时间 ); 参数说明: (1)hHandle:等待对象的对象句柄。该对象句柄必须为SYNCHRONIZE访问。 (2)dwMilliseconds:等待时间,单位为ms。若该值为0,函数在测试对象的状态后立即返回,若为INFINITE,函数一直等待下去,直到接收到 一个信号将其唤醒,如表2-1所示。 返回值: 如果成功返回,其返回值说明是何种事件导致函数返回。 Static HANDLE hHandlel = NULL; DWORD dRes; dRes = WaitForSingleObject(hHandlel,10); //等待对象的句柄为hHandlel,等待时间为10ms 2)等待对个对象 WaitForMultiple()bject()在指定时间内等待多个对象,它等待的对象与 WaitForSingleObject()相同。 原型: DWORD WaitForMultipleObjects( DWORD nCount, //句柄数组中的句柄数 CONST HANDLE * lpHandles, //指向对象句柄数组的指针 BOOL fWaitAll, //等待类型 DWORD dwMilliseconds //等待时间 ); 参数说明: (1)nCount:由指针 * lpHandles指定的句柄数组中的句柄数,最大数是MAXIMUM WAIT OBJECTS。 (2)* lpHandles:指向对象句柄数组的指针。 (3)fWaitAll:等待类型。若为TRUE,当由lpHandles数组指定的所有对象被唤醒时函数返回;若为FALSE,当由lpHandles数组指定的某一个 对象被唤醒时函数返回,且由返回值说明是由于哪个对象引起的函数 返回。 (4)dwMilliseconds:等待时间,单位为ms。若该值为0,函数测试对象的状态后立即返回;若为INFINITE,函数一直等待下去,直到接收到 一个信号将其唤醒。 返回值:、 如果成功返回,其返回值说明是何种事件导致函数返回。 各参数的描述如表2-2所示。操作系统实验三
操作系统课程设计答案
操作系统实验页面置换算法C++代码
操作系统原理-进程调度实验报告
操作系统实验实验1
操作系统实验报告一
操作系统原理实验-系统内存使用统计5
操作系统实验之内存管理实验报告
操作系统实验六磁盘调度算法正确C代码
计算机操作系统实验四
操作系统实验报告
操作系统B2-上机实验-进程
操作系统原理实验四
操作系统实验四
操作系统实验报告4
操作系统实验一
操作系统实验报告_实验五
操作系统实验全(五个)
操作系统原理实验五