操作系统实验报告.docx
《操作系统实验报告.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告.docx(22页珍藏版)》请在冰豆网上搜索。
操作系统实验报告
操作系统实验报告
实验三一个进程启动另一个程序的执行
【实验目的】
在Linux环境系统中,execve系统调用用于执行一个程序(可执行二进制文件或脚本)。
exec函数家族,包括execl、execlp、execle、execv、execvp,是execve系统调用的前端。
本实验要求学生学习在一个进程中启动另一个程序执行的基本方法,了解execve系统调用和exec函数家族的使用方法。
【实验内容】
(一)初步认识“在一个进程中启动另一个程序的执行”。
1、编辑一个源程序dummy.c,并编译为可执行程序dummy。
//dummy.c
#include
#include
#include
#include
intmain(intargc,char**argv)
{
intresult;
printf("\nYouarenowinarunningprogram\"%s\".\n",argv[0]);
printf("MyPIDis%d.Myparent'sPIDis%d.\n",getpid(),getppid());
printf(
"Pleaseinputaninteger(0-255),whichwillbereturnedtomyparentprocess:
\n");
scanf("%d",&result);
printf("Goodbye.\n\n");
return(result&0377);
}}
2、再编辑一个源程序exec_test.c,并编译为可执行程序exec_test。
//exec_test.c
#include
#include
#include
#include
#include
#include
intmain(intargc,char**argv)
{
intresult;
result=fork();
if(result<0)
{
perror("Failedtocreatechild");
exit
(1);
}
elseif(result==0)
{
//Child1
char*cmd="./dummy";
printf("Childprocess'sPIDis%d.Myparent'sPIDis%d.\n",getpid(),
getppid());
printf("Childprocessisabouttoexecute\"%s\"\n\n",cmd);
result=execlp(cmd,cmd,NULL);
if(result==-1)
{
perror("Inchildprocess,failedtoexecaprogram");
}
exit(0);
}
else
{
//parent
intstatus;
printf("Parentprocess'sPIDis%d.\n",getpid());
printf("Parentprocessiswaiting...\n");
wait(&status);
printf(
"Inparentprocess,status=0x%x,WEXITSTATUS(status)=%d(i.e.0x%x)\n",\
status,WEXITSTATUS(status),WEXITSTATUS(status));
}
return(EXIT_SUCCESS);
}
3、先执行dummy,观察、分析执行结果;然后执行程序exec_test,观察、分析执行结果。
(注意,两个可执行程序都在当前目录下)
(二)实现一个简单的命令解释外壳(Shell)。
1、基本功能:
(1)从标准输入读取一行字符串,其中包含欲执行的命令和它的命令行参数(如果有的话)。
提示:
需要将输入的一行字符串进行拆分,以空格、制表符(\t)作为分隔符,分解为命令、命令行参数(零个或多个)。
如果用户输入的命令是“quit”,则退出执行。
(2)创建一个子进程。
(3)在子进程中,执行在
(1)读入的命令,如果有命令行参数,也要传递。
(4)在父进程中,等待子进程结束,然后打印子进程的返回值。
(5)在父进程中,控制转移至
(1)。
【实验要求】
按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。
【实验设计】
dummy程序:
结果显示了该进程的PID和父进程的PID,并且将一个值返回给了父进程。
exec_test程序:
在子进程中键入的数值返回了父进程,并显示了出来(19).
实现一个简单的命令解释外壳(Shell)
源代码:
//example
#include
#include
#include
#include
#include
#include
#include
intmain(){
intpid;
intrtn;//子进程的返回值
intexec_errorno;
charcommand[256];
char*p;
char*q;
char*c[20];
inti=0,j=0;
while
(1){
//从终端读取要执行的命令
printf(">");
command[0]='\0';
p=fgets(command,256,stdin);
if(p==NULL){
perror("Errorinfgets().");
exit(-1);
}
//Deletethelastchar(newline)inthestringreturnedbyfgets()
command[strlen(command)-1]='\0';
p=command;
q=p;
//Quitifuserinputs"quit"
if(!
strcmp(command,"quit")){
break;
}
//Createachildprocesstoexecutecommand
pid=fork();
if(pid<0){
perror("Failedwhilecallingfork.");
exit(-1);
}
elseif(pid==0){
//子进程执行此命令
for(;;){
c[i]=strtok(p,"");
if(c[i]==NULL){
break;
}
i++;
p=NULL;
}
p=c[0];
for(j=0;j
printf("%s\n",c[j]);
}
exec_errorno=execvp(p,c);
//如果exec函数返回,表明没有正常执行命令
//只有在这种情况下,才会执行下面的打印错误信息
perror(command);
exit(exec_errorno);
}
else{
//父进程,等待子进程结束,并打印子进程的返回值
wait(&rtn);
printf("\nValuereturnedfromchildprocess,rtn=%d\n",rtn);
printf("WEXITSTATUS(rtn)=%d\n",WEXITSTATUS(rtn));
}
}
return0;
}
【实验测试结果及分析】
此程序通过对execvp()函数的调用,使得通过输入命令被执行。
输入的命令用fgets()存入command字符串中,然后反复调用strtok()函数,分割所得字符串,达到将命令分割的目的,使得多命令行参数得以实现。
【运行结果】
【收获及体会】
实验指导书在实验调试和分析的过程中,我越来越懂得自学能力和自我独立解决问题的重要性。
在以后的实验和学习中,我会不断的加强对这方面的训练。
【参考资料】
实验指导书
实验五线程间的互斥与同步
【实验目的】
理解POSIX线程(Pthread)互斥锁和POSIX信号量机制,学习它们的使用方法;编写程序,实现多个POSIX线程的同步控制。
【实验内容】
创建4个POSIX线程。
其中2个线程(A和B)分别从2个数据文件(data1.txt和data2.txt)
读取10个整数.线程A和B把从文件中读取的逐一整数放入一个缓冲池.缓冲池由n个缓
冲区构成(n=5,并可以方便地调整为其他值),每个缓冲区可以存放一个整数。
另外2个
线程,C和D,各从缓冲池读取10数据。
线程C、D每读出2个数据,分别求出它们的和
或乘积,并打印输出。
提示:
(1)在创建4个线程当中,A和B是生产者,负责从文件读取数据到公共的缓冲区,
C和D是消费者,从缓冲区读取数据然后作不同的计算(加和乘运算)。
使用互斥锁和信
号量控制这些线程的同步。
不限制线程C和D从缓冲区得到的数据来自哪个文件。
(2)在生产者线程中,确保从文件读出数据以后,再去“生产”。
在开始设计和实现之前,务必认真阅读下列内容:
课本6.8.4节;
讲义(课堂PPT)中关于“生产者-消费者问题”的部分;
课本第6章后面的编程项目——生产者-消费者问题。
【实验要求】
按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。
【实验设计】
#include
#include
#include
#include
#include
#defineNUM_THREADS5
intbuffer[5];
intin=0;//写入标识
intout=0;//读取标识
pthread_mutex_tmutex2in,mutex2out;
sem_twri,rea;
void*write1(void*arg)
{
FILE*fp1=fopen("data1.txt","r");
intw1;
inti1=0;
for(i1=0;i1<10;i1++)
{
//P(写资源)
sem_wait(&wri);
//从文件中读取一个文件
if(fscanf(fp1,"%d",&w1))
;
else
{
printf("I'mthepthreadwrite1,Ican'treadanumfromdata1.txt.\n");
exit
(1);
}
//放入缓存对应位置
//加in锁
pthread_mutex_lock(&mutex2in);
buffer[in]=w1;
in=(in+1)%NUM_THREADS;
//解in锁
pthread_mutex_unlock(&mutex2in);
//V(读资源)
sem_post(&rea);
}
//线程结束
fclose(fp1);
pthread_exit(NULL);
}
void*write2(void*arg)
{
intw2;
FILE*fp2=fopen("data2.txt","r");
inti2=0;
for(i2=0;i2<10;i2++)
{
//P(写资源)
sem_wait(&wri);
//从文件中读取一个文件
if(fscanf(fp2,"%d",&w2))
;
else
{
printf("I'mthepthreadwrite1,Ican'treadanumfromdata1.txt.\n");
exit
(1);
}
//放入缓存对应位置
//加in锁
pthread_mutex_lock(&mutex2in);
buffer[in]=w2;
in=(in+1)%NUM_THREADS;
//解in锁
pthread_mutex_unlock(&mutex2in);
//V(读资源)
sem_post(&rea);
}
//线程结束
fclose(fp2);
pthread_exit(NULL);
}
void*plus(void*arg)
{
//加进程
inta1,b1,c1;
intp=0;
for(p=0;p<5;p++)
{
//P(读资源)
sem_wait(&rea);
//从缓冲中读取一个文件
//加out锁
pthread_mutex_lock(&mutex2out);
a1=buffer[out];
out=(out+1)%NUM_THREADS;
//解out锁
pthread_mutex_unlock(&mutex2out);
//V(写资源)
sem_post(&wri);
//P(读资源)
sem_wait(&rea);
//加out锁
pthread_mutex_lock(&mutex2out);
//从缓冲中读取一个文件
b1=buffer[out];
out=(out+1)%NUM_THREADS;
//解out锁
pthread_mutex_unlock(&mutex2out);
c1=a1+b1;
//计算求和并且输出到屏幕
printf("I'mthepthreadofplusing,thisismyresult:
\t%d+%d=%d.\n",
a1,b1,c1);
//V(写资源)
sem_post(&wri);
}
//线程结束
pthread_exit(NULL);
}
void*mult(void*arg)
{
//乘进程
inta2,b2,c2;
intp=0;
for(p=0;p<5;p++)
{
//P(读资源)
sem_wait(&rea);
//加out锁
pthread_mutex_lock(&mutex2out);
//从缓冲中读取一个文件
a2=buffer[out];
out=(out+1)%NUM_THREADS;
//解out锁
pthread_mutex_unlock(&mutex2out);
//V(写资源)
sem_post(&wri);
//P(读资源)
sem_wait(&rea);
//加out锁
pthread_mutex_lock(&mutex2out);
//从缓冲中读取一个文件
b2=buffer[out];
out=(out+1)%NUM_THREADS;
//解out锁
pthread_mutex_unlock(&mutex2out);
c2=a2*b2;
//计算求积并且输出到屏幕
printf(
"I'mthepthreadofmultiplying,thisismyresult:
\t%d*%d=%d.\n",
a2,b2,c2);
//V(写资源)
sem_post(&wri);
}
//线程结束
pthread_exit(NULL);
}
intmain()
{
//互斥锁初始化
pthread_mutex_init(&mutex2in,NULL);
pthread_mutex_init(&mutex2out,NULL);
pthread_tA,B,C,D;
interr;
//信号量初始化
sem_init(&wri,0,5);
sem_init(&rea,0,0);
//创建线程1
err=pthread_create(&A,NULL,write1,NULL);
if(err!
=0)
{
printf("can'tcreatemyThread1:
%s\n",strerror(err));
}
//创建线程2
err=pthread_create(&B,NULL,write2,NULL);
if(err!
=0)
{
printf("can'tcreatemyThread2:
%s\n",strerror(err));
}
//稍微延迟
sleep(0.1);
//创建线程3
err=pthread_create(&C,NULL,plus,NULL);
if(err!
=0)
{
printf("can'tcreatemyThread3:
%s\n",strerror(err));
}
//创建线程4
err=pthread_create(&D,NULL,mult,NULL);
if(err!
=0)
{
printf("can'tcreatemyThread4:
%s\n",strerror(err));
}
pthread_join(A,NULL);
pthread_join(B,NULL);
pthread_join(C,NULL);
pthread_join(D,NULL);
return0;
}
【收获及体会】
在完成上次实验时,我在网上找到了一片相关文章,里面稍有提及互斥锁的知识,当时我粗略看了一下。
没想到这次试验的主体内容就是使用互斥锁和信号量。
简而言之,互斥锁是对互斥资源进行限制访问,以防止不同线程(进程)同时对某个资源进行访问,而导致资源的状态不明,出乎意料,用来实现互斥的。
进而在使用共有资源时,例如本题中的标识量in,out时候,就需要加锁和解锁,以达到在访问in,out时候,只有某一个线程访问此资源,就不会导致资源的状态混乱。
而信号量是用于实现进程同步的,一般是为了使若干线程(进程)之间运行先后有序。
本例中,读取线程一定要在计算线程之前,因而使用信号量,来控制线程之间的先后顺序。
通过本次实验,我也复习了之前学过的一些C语言知识。
包括文件的读取与写入,线程的创建与结束等。
这次实验很有意义,我收获很多。
【参考资料】
实验指导书