操作系统实验实验25.docx
《操作系统实验实验25.docx》由会员分享,可在线阅读,更多相关《操作系统实验实验25.docx(19页珍藏版)》请在冰豆网上搜索。
操作系统实验实验25
实验二
进入VI编辑器
格式:
vi文件名
例:
visy.c
Vi编辑器三种工作方式:
1.编辑方式:
进入VI处于编辑方式
2.文本输入方式:
在编辑方式下输入a,进入追加方式,输入i,进入插入方式
3.命令方式:
在输入方式下,按Esc键,由文本输入转向编辑方式,输入冒号:
进入命令方式
4.退出vi
:
wq写文件退出
:
wwenjianming写文件
q!
不写退出
wq!
写退出
编译c文件
Gcc-owenjianming.outwenjianming.c
运行文件:
./wenjianming.out
1.实验内容和目的
用vi编辑器编辑下列文件,使用gcc编译器和gdb调试器,对下列程序编译运行,分析运行结果。
要求至少完成3个程序。
2.程序示例
(1)/*父子进程之间的同步之例*/
#include
main()
{
intpid1;
if(pid1=fork())/*createchild1*/
{if(fork())/*createthechild2*/
{printf(“parent’scontext.\n”);
printf(“parentiswaitingthechild1terminate.\n);
wait(0);
printf(“parentiswaitingthechild2terminate.\n”);
printf(“parentterminate.\n”);
exit(0);
}
else
/*child2*/
printf(“child2’scontext.\n”);
sleep(5);
printf(“child2terminate.\n”);
else{if(pid1==0)/*child1*/
{printf(“child1’scontext.\n”);
sleep(10);
printf(“child1terminate.\n”);
分析:
上述程序是父进程首先创建一个子进程,若成功,再创建另一个子进程,之后三个进程并发执行。
究竟谁先执行,是随机的,可根据执行结果判断。
试分析该程序的所有运行结果。
注释:
fork()调用正确完成时,给父进程返回地是被创建子进程的标识,给子进程返回的是0;创建失败时,返回给父进程的时-1;
exit(0)进程终止自己
wait(0)父进程同步等待子进程结束,即无子进程结束,父进程等待。
(2)管道通信机制
通过使用管道实现两个和多个进程之间的通信。
所谓管道,就是将一个进程的标准输出与另一个进程的标准输入联系在一起,进行通信的一种方法。
同组进程之间可用无名管道进行通信,不同组进程可通过有名管道通信。
使用无名管道进行父子进程之间的通信
#include
intpipe(intfiledes[2]);
charparent[]=”amessagetopipe’communication.\n”;
{intpid,chan1[2];
charbuf[100];
pipe(chan1);
pid=fork();
if(pid<0)
{printf(“tocreatechilderror\n”);
exit
(1);
if(pid>0)
{close(chan1[0]);/*父进程关闭读通道*/
printf(“parentprocesssendsamessagetochild.\n”);
write(chan1[1],parent,sizeof(parent));
close(chan1[1]);
printf(“parentprocesswaitsthechildtoterminate.\n”);
printf(“parentprocessterminates.\n”);
else{
close(chan1[1]);/*子进程关闭写通道*/
read(chan1[0],buf,100);
printf(“themessagereadbychildprocessformparentis%s.\n”,buf);
close(chan1[0]);
printf(“childprocessterminates\n”);
观察运行结果。
pipe(intfiledes[2]):
创建一个无名管道,filedes[0]为读通道,filedes[1]为写通道。
(3)Linux中的多线程编程threads.c
#defineMAX10
pthread_tthread[2];
pthread_mutex_tmut;
intnumber=0,i;
void*thread1()
printf("thread1:
I'mthread1\n");
for(i=0;i{printf("thread1:number=%d\n",number);pthread_mutex_lock(&mut);number++;pthread_mutex_unlock(&mut);sleep(2);}printf("thread1:主函数在等我完成任务吗?\n");pthread_exit(NULL);}void*thread2(){printf("thread2:I'mthread2\n");for(i=0;i{printf("thread2:number=%d\n",number);pthread_mutex_lock(&mut);number++;pthread_mutex_unlock(&mut);sleep(3);}printf("thread2:主函数在等我完成任务吗?\n");pthread_exit(NULL);}voidthread_create(void){inttemp;memset(&thread,0,sizeof(thread));//comment1/*创建线程*/if((temp=pthread_create(&thread[0],NULL,thread1,NULL))!=0)//comment2printf("线程1创建失败!\n");elseprintf("线程1被创建\n");if((temp=pthread_create(&thread[1],NULL,thread2,NULL))!=0)//comment3printf("线程2创建失败");elseprintf("线程2被创建\n");}voidthread_wait(void){/*等待线程结束*/if(thread[0]!=0){//comment4pthread_join(thread[0],NULL);printf("线程1已经结束\n");}if(thread[1]!=0){//comment5pthread_join(thread[1],NULL);printf("线程2已经结束\n");}}intmain(){/*用默认属性初始化互斥锁*/pthread_mutex_init(&mut,NULL);printf("我是主函数哦,我正在创建线程,呵呵\n");thread_create();printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n");thread_wait();return0;}3.注意:Gcc–lpthread–othread.outthread.c线程相关操作1)pthread_tpthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:typedefunsignedlongintpthread_t;它是一个线程的标识符。2)pthread_create函数pthread_create用来创建一个线程,它的原型为:externintpthread_create__P((pthread_t*__thread,__constpthread_attr_t*__attr,void*(*__start_routine)(void*),void*__arg));第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。3)pthread_joinpthread_exit函数pthread_join用来等待一个线程的结束。函数原型为:externintpthread_join__P((pthread_t__th,void**__thread_return));第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:externvoidpthread_exit__P((void*__retval))__attribute__((__noreturn__));唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit。下面,我们来了解线程的一些常用属性以及如何设置这些属性。互斥锁相关互斥锁用来保证一段时间内只有一个线程在执行一段代码。1)pthread_mutex_init函数pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,须调用函数pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函数pthread_mutexattr_settype用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_PRIVATE。后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD_MUTEX_DEFAULT。它们分别定义了不同的上锁、解锁机制,一般情况下,选用最后一个默认属性。2)pthread_mutex_lockpthread_mutex_unlockpthread_delay_nppthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。注意:1)需要说明的是,上面的两处sleep不光是为了演示的需要,也是为了让线程睡眠一段时间,让线程释放互斥锁,等待另一个线程使用此锁。2)请千万要注意里头的注释comment1-5,如果没有comment1和comment4,comment5,将导致在pthread_join的时候出现段错误,另外,上面的comment2和comment3是根源所在,所以千万要记得写全代码。因为上面的线程可能没有创建成功,导致下面不可能等到那个线程结束,而在用pthread_join的时候出现段错误(访问了未知的内存区)。另外,在使用memset的时候,需要包含string.h头文件。实验报告(1)实验题目。(2)说明对程序的理解,程序后加上注释语句。(3)分析程序的执行结果并加以解释。实验三1.实验内容与目的熟悉有关文件的系统调用,学习文件系统的系统调用命令,提高对文件系统实现功能的理解和掌握。使用creatopenreadwrite等系统调用用C语言编程实现复制文件。2.注释(1)Intcreat(constchar*pathname,mode_tmode);返回值:如果正确创建,返回文件的描述符;否则返回-1;Pathname是要创建文件的路径名。创建文件时,文件只能以只写方式打开Mode用来规定该文件的拥有者,小组用户和其他用户的访问权限,要求用按位逻辑加对下列符号常量进行所需的组合(同open函数)。(2)intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);intclose(intfd);open函数有两个形式.其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合.O_RDONLY:以只读的方式打开文件.O_WRONLY:以只写的方式打开文件.O_RDWR:以读写的方式打开文件.O_APPEND:以追加的方式打开文件.O_CREAT:创建一个文件.O_EXEC:如果使用了O_CREAT而且文件已经存在,就会发生一个错误.O_NOBLOCK:以非阻塞的方式打开一个文件.O_TRUNC:如果文件已经存在,则删除文件的内容.前面三个标志只能使用任意的一个.如果使用了O_CREATE标志,那么我们要使用open的第二种形式.还要指定mode标志,用来表示文件的访问权限.mode可以是以下情况的组合.-----------------------------------------------------------------S_IRUSR用户可以读S_IWUSR用户可以写S_IXUSR用户可以执行S_IRWXU用户可以读写执行-----------------------------------------------------------------S_IRGRP组可以读S_IWGRP组可以写S_IXGRP组可以执行S_IRWXG组可以读写执行-----------------------------------------------------------------S_IROTH其他人可以读S_IWOTH其他人可以写S_IXOTH其他人可以执行S_IRWXO其他人可以读写执行-----------------------------------------------------------------S_ISUID设置用户执行IDS_ISGID设置组的执行ID-----------------------------------------------------------------我们也可以用数字来代表各个位的标志.Linux总共用5个数字来表示文件的各种权限.00000.第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限.每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和.比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户ID位那么我们可以使用的模式是--1(设置用户ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省)5(1+4)即10705:open("temp",O_CREAT,10705);如果我们打开文件成功,open会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描述符进行操作了.当我们操作完成以后,我们要关闭文件了,只要调用close就可以了,其中fd是我们要关闭的文件描述符.(3)ssize_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,constvoid*buffer,size_tcount);fd是我们要进行读写操作的文件描述符,buffer是我们要写入文件内容或读出文件内容的内存地址.count是我们要读写的字节数.对于普通的文件read从指定的文件(fd)中读取count字节到buffer缓冲区中(记住我们必须提供一个足够大的缓冲区),同时返回count.如果read读到了文件的结尾或者被一个信号所中断,返回值会小于count.如果是由信号中断引起返回,而且没有返回数据,read会返回-1,且设置errno为EINTR.当程序读到了文件结尾的时候,read会返回0.write从buffer中写count字节到文件fd中,成功时返回实际所写的字节数.可能用到的头文件#include#include#include#include#include4.实验报告(1)实验题目。(2)采用的数据结构及符号说明。(3)打印一份源程序清单,并附加流程图与注释。(4)分析文件系统中常用的系统调用。实验四模拟内存管理程序(4学时)1、实验目的了解简单的固定大小内存分配方法,掌握分区存储管理技术,了解在分区管理机制下所需的数据结构。2、实验内容1)、将1024K内存按如下块大小分成十个内存块。内存块号内存块大小起始地址内存块状态151210NO2256522NO3256778NO41281034NO51281162NO61281290NO7321418NO8321450NO9161482NO10161498NO其中,在内存状态中用NO代表该内存块未被分配;用进程名代表该内存块已被分配。2)、编制模拟内存管理程序,根据调入内存的进程大小分别采用最先适应法和最佳适应法分配内存块。最佳适应法,如有一个12K的程序被运行时,它应该被分配到内存块号9,若有200K的程序运行时,应将其调入内存块号2。最先适应法,则是按内存块号的顺序,依次放入各进程名。有关编程请仔细阅读后面的参考流程。3、实验要求1)、要求通过键盘输入若干进程名称和程序所占内存空间的大小,把这些进程分配到内存表中,显示内存分配情况。2)、编制程序可以循环输入,输入某进程结束或某进程添加进来、进程占用存储空间的大小,并显示内存分配情况。3)、当没有区间存放程序时,应有提示。4)、所编写的程序,应有退出功能。5)、每添加、结束一个进程,应有输出显示,输出显示的格式如下:内存块号内存块大小起始地址进程名(内存状态)151210A12256522NO3256778A241281034A351281162NO61281290NO7321418NO8321450NO9161482NO10161498NO4、实验报告格式要求1)、实验题目2)、程序所采用的数据结构、符号说明,及采用哪一种内存分配方法3)、写出源程序清单,要求附加流程图与注释4)、写出内存分配的变化情况实验五进程管理设计一.目的和要求进程调度是处理机管理的核心内容。本实验要求用C语言编写和调试一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数和时间片轮转调度算法的具体实施办法。二.实验内容1.设计进程控制块PCB表结构,分别适用于优先数调度算法和循环轮转算法。PCB结构通常包括以下信息:进程名、进程优先数(或轮转时间片)、进程所占用的CPU时间、进程的状态、当前队列指针等。根据调度算法的不同,PCB结构的内容可以做适当的删除。2.建立进程就绪队列,对两种不同算法编制入链子程序。3.编制两种进程调度算法:1)优先数调度;2)循环轮转调度。三.实验环境1.IBM286以上微型计算机及其兼容机。2.DOS系统要求3.3及更高的版本。3.TURBOC2.0。四.实验要求本实验要求用C语言编写,选用优先数算法和简单时间片轮转法对五个进程进行调度,每个进程可以有三种状态:运行状态(RUN)、就绪状态(READY)和完成状态(FINISH)。并假定初始状态为就绪状态。五.模拟算法提示1.数据结构设计进程控制块结构如下:PCB:NAMEPRIO/RO
number=%d\n",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep
(2);
主函数在等我完成任务吗?
\n");
pthread_exit(NULL);
void*thread2()
printf("thread2:
I'mthread2\n");
for(i=0;i{printf("thread2:number=%d\n",number);pthread_mutex_lock(&mut);number++;pthread_mutex_unlock(&mut);sleep(3);}printf("thread2:主函数在等我完成任务吗?\n");pthread_exit(NULL);}voidthread_create(void){inttemp;memset(&thread,0,sizeof(thread));//comment1/*创建线程*/if((temp=pthread_create(&thread[0],NULL,thread1,NULL))!=0)//comment2printf("线程1创建失败!\n");elseprintf("线程1被创建\n");if((temp=pthread_create(&thread[1],NULL,thread2,NULL))!=0)//comment3printf("线程2创建失败");elseprintf("线程2被创建\n");}voidthread_wait(void){/*等待线程结束*/if(thread[0]!=0){//comment4pthread_join(thread[0],NULL);printf("线程1已经结束\n");}if(thread[1]!=0){//comment5pthread_join(thread[1],NULL);printf("线程2已经结束\n");}}intmain(){/*用默认属性初始化互斥锁*/pthread_mutex_init(&mut,NULL);printf("我是主函数哦,我正在创建线程,呵呵\n");thread_create();printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n");thread_wait();return0;}3.注意:Gcc–lpthread–othread.outthread.c线程相关操作1)pthread_tpthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:typedefunsignedlongintpthread_t;它是一个线程的标识符。2)pthread_create函数pthread_create用来创建一个线程,它的原型为:externintpthread_create__P((pthread_t*__thread,__constpthread_attr_t*__attr,void*(*__start_routine)(void*),void*__arg));第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。3)pthread_joinpthread_exit函数pthread_join用来等待一个线程的结束。函数原型为:externintpthread_join__P((pthread_t__th,void**__thread_return));第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:externvoidpthread_exit__P((void*__retval))__attribute__((__noreturn__));唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit。下面,我们来了解线程的一些常用属性以及如何设置这些属性。互斥锁相关互斥锁用来保证一段时间内只有一个线程在执行一段代码。1)pthread_mutex_init函数pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,须调用函数pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函数pthread_mutexattr_settype用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_PRIVATE。后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD_MUTEX_DEFAULT。它们分别定义了不同的上锁、解锁机制,一般情况下,选用最后一个默认属性。2)pthread_mutex_lockpthread_mutex_unlockpthread_delay_nppthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。注意:1)需要说明的是,上面的两处sleep不光是为了演示的需要,也是为了让线程睡眠一段时间,让线程释放互斥锁,等待另一个线程使用此锁。2)请千万要注意里头的注释comment1-5,如果没有comment1和comment4,comment5,将导致在pthread_join的时候出现段错误,另外,上面的comment2和comment3是根源所在,所以千万要记得写全代码。因为上面的线程可能没有创建成功,导致下面不可能等到那个线程结束,而在用pthread_join的时候出现段错误(访问了未知的内存区)。另外,在使用memset的时候,需要包含string.h头文件。实验报告(1)实验题目。(2)说明对程序的理解,程序后加上注释语句。(3)分析程序的执行结果并加以解释。实验三1.实验内容与目的熟悉有关文件的系统调用,学习文件系统的系统调用命令,提高对文件系统实现功能的理解和掌握。使用creatopenreadwrite等系统调用用C语言编程实现复制文件。2.注释(1)Intcreat(constchar*pathname,mode_tmode);返回值:如果正确创建,返回文件的描述符;否则返回-1;Pathname是要创建文件的路径名。创建文件时,文件只能以只写方式打开Mode用来规定该文件的拥有者,小组用户和其他用户的访问权限,要求用按位逻辑加对下列符号常量进行所需的组合(同open函数)。(2)intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);intclose(intfd);open函数有两个形式.其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合.O_RDONLY:以只读的方式打开文件.O_WRONLY:以只写的方式打开文件.O_RDWR:以读写的方式打开文件.O_APPEND:以追加的方式打开文件.O_CREAT:创建一个文件.O_EXEC:如果使用了O_CREAT而且文件已经存在,就会发生一个错误.O_NOBLOCK:以非阻塞的方式打开一个文件.O_TRUNC:如果文件已经存在,则删除文件的内容.前面三个标志只能使用任意的一个.如果使用了O_CREATE标志,那么我们要使用open的第二种形式.还要指定mode标志,用来表示文件的访问权限.mode可以是以下情况的组合.-----------------------------------------------------------------S_IRUSR用户可以读S_IWUSR用户可以写S_IXUSR用户可以执行S_IRWXU用户可以读写执行-----------------------------------------------------------------S_IRGRP组可以读S_IWGRP组可以写S_IXGRP组可以执行S_IRWXG组可以读写执行-----------------------------------------------------------------S_IROTH其他人可以读S_IWOTH其他人可以写S_IXOTH其他人可以执行S_IRWXO其他人可以读写执行-----------------------------------------------------------------S_ISUID设置用户执行IDS_ISGID设置组的执行ID-----------------------------------------------------------------我们也可以用数字来代表各个位的标志.Linux总共用5个数字来表示文件的各种权限.00000.第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限.每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和.比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户ID位那么我们可以使用的模式是--1(设置用户ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省)5(1+4)即10705:open("temp",O_CREAT,10705);如果我们打开文件成功,open会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描述符进行操作了.当我们操作完成以后,我们要关闭文件了,只要调用close就可以了,其中fd是我们要关闭的文件描述符.(3)ssize_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,constvoid*buffer,size_tcount);fd是我们要进行读写操作的文件描述符,buffer是我们要写入文件内容或读出文件内容的内存地址.count是我们要读写的字节数.对于普通的文件read从指定的文件(fd)中读取count字节到buffer缓冲区中(记住我们必须提供一个足够大的缓冲区),同时返回count.如果read读到了文件的结尾或者被一个信号所中断,返回值会小于count.如果是由信号中断引起返回,而且没有返回数据,read会返回-1,且设置errno为EINTR.当程序读到了文件结尾的时候,read会返回0.write从buffer中写count字节到文件fd中,成功时返回实际所写的字节数.可能用到的头文件#include#include#include#include#include4.实验报告(1)实验题目。(2)采用的数据结构及符号说明。(3)打印一份源程序清单,并附加流程图与注释。(4)分析文件系统中常用的系统调用。实验四模拟内存管理程序(4学时)1、实验目的了解简单的固定大小内存分配方法,掌握分区存储管理技术,了解在分区管理机制下所需的数据结构。2、实验内容1)、将1024K内存按如下块大小分成十个内存块。内存块号内存块大小起始地址内存块状态151210NO2256522NO3256778NO41281034NO51281162NO61281290NO7321418NO8321450NO9161482NO10161498NO其中,在内存状态中用NO代表该内存块未被分配;用进程名代表该内存块已被分配。2)、编制模拟内存管理程序,根据调入内存的进程大小分别采用最先适应法和最佳适应法分配内存块。最佳适应法,如有一个12K的程序被运行时,它应该被分配到内存块号9,若有200K的程序运行时,应将其调入内存块号2。最先适应法,则是按内存块号的顺序,依次放入各进程名。有关编程请仔细阅读后面的参考流程。3、实验要求1)、要求通过键盘输入若干进程名称和程序所占内存空间的大小,把这些进程分配到内存表中,显示内存分配情况。2)、编制程序可以循环输入,输入某进程结束或某进程添加进来、进程占用存储空间的大小,并显示内存分配情况。3)、当没有区间存放程序时,应有提示。4)、所编写的程序,应有退出功能。5)、每添加、结束一个进程,应有输出显示,输出显示的格式如下:内存块号内存块大小起始地址进程名(内存状态)151210A12256522NO3256778A241281034A351281162NO61281290NO7321418NO8321450NO9161482NO10161498NO4、实验报告格式要求1)、实验题目2)、程序所采用的数据结构、符号说明,及采用哪一种内存分配方法3)、写出源程序清单,要求附加流程图与注释4)、写出内存分配的变化情况实验五进程管理设计一.目的和要求进程调度是处理机管理的核心内容。本实验要求用C语言编写和调试一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数和时间片轮转调度算法的具体实施办法。二.实验内容1.设计进程控制块PCB表结构,分别适用于优先数调度算法和循环轮转算法。PCB结构通常包括以下信息:进程名、进程优先数(或轮转时间片)、进程所占用的CPU时间、进程的状态、当前队列指针等。根据调度算法的不同,PCB结构的内容可以做适当的删除。2.建立进程就绪队列,对两种不同算法编制入链子程序。3.编制两种进程调度算法:1)优先数调度;2)循环轮转调度。三.实验环境1.IBM286以上微型计算机及其兼容机。2.DOS系统要求3.3及更高的版本。3.TURBOC2.0。四.实验要求本实验要求用C语言编写,选用优先数算法和简单时间片轮转法对五个进程进行调度,每个进程可以有三种状态:运行状态(RUN)、就绪状态(READY)和完成状态(FINISH)。并假定初始状态为就绪状态。五.模拟算法提示1.数据结构设计进程控制块结构如下:PCB:NAMEPRIO/RO
sleep(3);
voidthread_create(void)
inttemp;
memset(&thread,0,sizeof(thread));//comment1
/*创建线程*/
if((temp=pthread_create(&thread[0],NULL,thread1,NULL))!
=0)//comment2
printf("线程1创建失败!
printf("线程1被创建\n");
if((temp=pthread_create(&thread[1],NULL,thread2,NULL))!
=0)//comment3
printf("线程2创建失败");
printf("线程2被创建\n");
voidthread_wait(void)
/*等待线程结束*/
if(thread[0]!
=0){//comment4
pthread_join(thread[0],NULL);
printf("线程1已经结束\n");
if(thread[1]!
=0){//comment5
pthread_join(thread[1],NULL);
printf("线程2已经结束\n");
intmain()
/*用默认属性初始化互斥锁*/
pthread_mutex_init(&mut,NULL);
printf("我是主函数哦,我正在创建线程,呵呵\n");
thread_create();
printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n");
thread_wait();
return0;
3.注意:
Gcc–lpthread–othread.outthread.c
线程相关操作
1)pthread_t
pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:
typedefunsignedlongintpthread_t;
它是一个线程的标识符。
2)pthread_create
函数pthread_create用来创建一个线程,它的原型为:
externintpthread_create__P((pthread_t*__thread,__constpthread_attr_t*__attr,
void*(*__start_routine)(void*),void*__arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。
这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。
第二个参数我们也设为空指针,这样将生成默认属性的线程。
对线程属性的设定和修改我们将在下一节阐述。
当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。
前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。
创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
3)pthread_joinpthread_exit
函数pthread_join用来等待一个线程的结束。
函数原型为:
externintpthread_join__P((pthread_t__th,void**__thread_return));
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。
这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。
一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。
它的函数原型为:
externvoidpthread_exit__P((void*__retval))__attribute__((__noreturn__));
唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。
最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。
在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit。
下面,我们来了解线程的一些常用属性以及如何设置这些属性。
互斥锁相关
互斥锁用来保证一段时间内只有一个线程在执行一段代码。
1)pthread_mutex_init
函数pthread_mutex_init用来生成一个互斥锁。
NULL参数表明使用默认属性。
如果需要声明特定属性的互斥锁,须调用函数pthread_mutexattr_init。
函数pthread_mutexattr_setpshared和函数pthread_mutexattr_settype用来设置互斥锁属性。
前一个函数设置属性pshared,它有两个取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。
前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。
在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_PRIVATE。
后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD_MUTEX_DEFAULT。
它们分别定义了不同的上锁、解锁机制,一般情况下,选用最后一个默认属性。
2)pthread_mutex_lockpthread_mutex_unlockpthread_delay_np
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。
当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。
注意:
1)需要说明的是,上面的两处sleep不光是为了演示的需要,也是为了让线程睡眠一段时间,让线程释放互斥锁,等待另一个线程使用此锁。
2)请千万要注意里头的注释comment1-5,如果没有comment1和comment4,comment5,将导致在pthread_join的时候出现段错误,另外,上面的comment2和comment3是根源所在,所以千万要记得写全代码。
因为上面的线程可能没有创建成功,导致下面不可能等到那个线程结束,而在用pthread_join的时候出现段错误(访问了未知的内存区)。
另外,在使用memset的时候,需要包含string.h头文件。
实验报告
(1)实验题目。
(2)说明对程序的理解,程序后加上注释语句。
(3)分析程序的执行结果并加以解释。
实验三
1.实验内容与目的
熟悉有关文件的系统调用,学习文件系统的系统调用命令,提高对文件系统实现功能的理解和掌握。
使用creatopenreadwrite等系统调用用C语言编程实现复制文件。
2.注释
(1)Intcreat(constchar*pathname,mode_tmode);
返回值:
如果正确创建,返回文件的描述符;否则返回-1;
Pathname是要创建文件的路径名。
创建文件时,文件只能以只写方式打开
Mode用来规定该文件的拥有者,小组用户和其他用户的访问权限,要求用按位逻辑加对下列符号常量进行所需的组合(同open函数)。
(2)intopen(constchar*pathname,intflags);
intopen(constchar*pathname,intflags,mode_tmode);
intclose(intfd);
open函数有两个形式.其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合.
O_RDONLY:
以只读的方式打开文件.
O_WRONLY:
以只写的方式打开文件.
O_RDWR:
以读写的方式打开文件.
O_APPEND:
以追加的方式打开文件.
O_CREAT:
创建一个文件.
O_EXEC:
如果使用了O_CREAT而且文件已经存在,就会发生一个错误.
O_NOBLOCK:
以非阻塞的方式打开一个文件.
O_TRUNC:
如果文件已经存在,则删除文件的内容.
前面三个标志只能使用任意的一个.如果使用了O_CREATE标志,那么我们要使用open的第二种形式.还要指定mode标志,用来表示文件的访问权限.mode可以是以下情况的组合.
-----------------------------------------------------------------
S_IRUSR用户可以读S_IWUSR用户可以写
S_IXUSR用户可以执行S_IRWXU用户可以读写执行
S_IRGRP组可以读S_IWGRP组可以写
S_IXGRP组可以执行S_IRWXG组可以读写执行
S_IROTH其他人可以读S_IWOTH其他人可以写
S_IXOTH其他人可以执行S_IRWXO其他人可以读写执行
S_ISUID设置用户执行IDS_ISGID设置组的执行ID
我们也可以用数字来代表各个位的标志.Linux总共用5个数字来表示文件的各种权限.
00000.第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限.
每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和.
比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户ID位那么我们可以使用的模式是--1(设置用户ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省)5(1+4)即10705:
open("temp",O_CREAT,10705);
如果我们打开文件成功,open会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描述符进行操作了.
当我们操作完成以后,我们要关闭文件了,只要调用close就可以了,其中fd是我们要关闭的文件描述符.
(3)ssize_tread(intfd,void*buffer,size_tcount);
ssize_twrite(intfd,constvoid*buffer,size_tcount);
fd是我们要进行读写操作的文件描述符,buffer是我们要写入文件内容或读出文件内容的内存地址.count是我们要读写的字节数.
对于普通的文件read从指定的文件(fd)中读取count字节到buffer缓冲区中(记住我们必须提供一个足够大的缓冲区),同时返回count.
如果read读到了文件的结尾或者被一个信号所中断,返回值会小于count.如果是由信号中断引起返回,而且没有返回数据,read会返回-1,且设置errno为EINTR.当程序读到了文件结尾的时候,read会返回0.
write从buffer中写count字节到文件fd中,成功时返回实际所写的字节数.
可能用到的头文件
4.实验报告
(2)采用的数据结构及符号说明。
(3)打印一份源程序清单,并附加流程图与注释。
(4)分析文件系统中常用的系统调用。
实验四模拟内存管理程序(4学时)
1、实验目的
了解简单的固定大小内存分配方法,掌握分区存储管理技术,了解在分区管理机制下所需的数据结构。
2、实验内容
1)、将1024K内存按如下块大小分成十个内存块。
内存块号内存块大小起始地址内存块状态
151210NO
2256522NO
3256778NO
41281034NO
51281162NO
61281290NO
7321418NO
8321450NO
9161482NO
10161498NO
其中,在内存状态中用NO代表该内存块未被分配;用进程名代表该内存块已被分配。
2)、编制模拟内存管理程序,根据调入内存的进程大小分别采用最先适应法和最佳适应法分配内存块。
最佳适应法,如有一个12K的程序被运行时,它应该被分配到内存块号9,若有200K的程序运行时,应将其调入内存块号2。
最先适应法,则是按内存块号的顺序,依次放入各进程名。
有关编程请仔细阅读后面的参考流程。
3、实验要求
1)、要求通过键盘输入若干进程名称和程序所占内存空间的大小,把这些进程分配到内存表中,显示内存分配情况。
2)、编制程序可以循环输入,输入某进程结束或某进程添加进来、进程占用存储空间的大小,并显示内存分配情况。
3)、当没有区间存放程序时,应有提示。
4)、所编写的程序,应有退出功能。
5)、每添加、结束一个进程,应有输出显示,输出显示的格式如下:
内存块号内存块大小起始地址进程名(内存状态)
151210A1
3256778A2
41281034A3
4、实验报告格式要求
1)、实验题目
2)、程序所采用的数据结构、符号说明,及采用哪一种内存分配方法
3)、写出源程序清单,要求附加流程图与注释
4)、写出内存分配的变化情况
实验五进程管理设计
一.目的和要求
进程调度是处理机管理的核心内容。
本实验要求用C语言编写和调试一个简单的进程调度程序。
通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数和时间片轮转调度算法的具体实施办法。
二.实验内容
1.设计进程控制块PCB表结构,分别适用于优先数调度算法和循环轮转算法。
PCB结构通常包括以下信息:
进程名、进程优先数(或轮转时间片)、进程所占用的CPU时间、进程的状态、当前队列指针等。
根据调度算法的不同,PCB结构的内容可以做适当的删除。
2.建立进程就绪队列,对两种不同算法编制入链子程序。
3.编制两种进程调度算法:
1)优先数调度;2)循环轮转调度。
三.实验环境
1.IBM286以上微型计算机及其兼容机。
2.DOS系统要求3.3及更高的版本。
3.TURBOC2.0。
四.实验要求
本实验要求用C语言编写,选用优先数算法和简单时间片轮转法对五个进程进行调度,每个进程可以有三种状态:
运行状态(RUN)、就绪状态(READY)和完成状态(FINISH)。
并假定初始状态为就绪状态。
五.模拟算法提示
1.数据结构
设计进程控制块结构如下:
PCB:
NAME
PRIO/RO
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1