操作系统实践报告.docx
《操作系统实践报告.docx》由会员分享,可在线阅读,更多相关《操作系统实践报告.docx(28页珍藏版)》请在冰点文库上搜索。
![操作系统实践报告.docx](https://file1.bingdoc.com/fileroot1/2023-7/16/39a57511-5b14-43e4-8c25-5e5bfec99c50/39a57511-5b14-43e4-8c25-5e5bfec99c501.gif)
操作系统实践报告
操作系统实践报告
多进程题目
:
实现shell程序,要求具备如下功能
支持命令参数
$echoarg1arg2arg3
$ls/bin/usr/bin/home
实现内置命令cd、pwd、exit
$cd/bin
$pwd
/bin
思路:
说明:
首先设置一个死循环模仿shell终端,读取用户的输入,并且根据空格将输入拆分成字符串数组,然后调用excute这个子函数进行处理。
1.echo
根据数组第一个元素来判断命令是什么,判断出是ehco后,fork一个新的进程,将其后的内容一个个输出出来,并且父进程等待子进程退出后再执行,确保输出在屏幕上时不被打断。
2.ls
3.读取用户输入并且根据拆分的数组判断出是ls命令后,fork一个新的进程,调用execlp函数将/bin/ls下的ls程序装入子进程并将拆分的数组参数部分传递给ls即可,同样的,父进程等待子进程退出,确保输出在屏幕上不被打断。
4.cd
5.同样是根据输入并拆分成数组后判断出是cd命令后,fork一个新的进程,然后调用chdir并将拆分数组的参数部分传递给chdir作为实参即可。
6.pwd
同样是根据输入并拆分成数组后判断出是pwd命令后,fork一个新的进程,然后调用system("pwd")即可,此命令也可以用来验证上面的cd命令是否正确执行。
7.exit
8.根据用户输入逼格拆分的数组判断出是exit命令后,excute子函数返回-1,在循环中检测excute的返回值,如果是-1则直接return,退出模仿的shell终端。
:
实现shell程序,要求在第1版的基础上,添加如下功能
实现文件重定向
$echohello>log
$catlog
Hello
思路:
接的描述,若判断出是echo命令后,要再次判断拆分的字符串数组中有无“>”出现,如果有,则把“>”之前、echo之后的内容作为输出,把“>”之后到“>”之后的第一个空白字符作为文件名,fopen创建文件并fwrite将输出内容输出到该文件中,并关闭文件。
和的源代码:
#include<>
#include<>
#include<>
#include<>
#include
#include
#include<>
#defineLEN256
#defineWIDTH256
#defineHEIGHT10
voidsplit(charsource[],chardest[HEIGHT][WIDTH])
{
char*p;
p=strsep(&source,"");
inti=0;
for(i=0;p[i]!
='\0';i++){
dest[0][i]=p[i];
}
dest[0][i]='\0';
intj=1;
while(p){
p=strsep(&source,"");
if(p){
for(i=0;p[i]!
='\0';i++){
dest[j][i]=p[i];
}
dest[j][i]='\0';
j++;
}
}
}
intexecute(charcomm[HEIGHT][WIDTH])
{
if(strcmp(comm[0],"echo")==0){
intpid=fork();
if(pid==0){
inti=0;
intis=0;
for(i=1;comm[i][0]!
='\0';i++){
if(comm[i][0]=='>'){
is=1;
break;
}
}
if(is==1){
puts(comm[i+1]);
FILE*fp=fopen(comm[i+1],"w+");
intj=0;
for(j=1;j
fseek(fp,0,SEEK_END);
fwrite(comm[j],strlen(comm[j]),1,fp);
}
fclose(fp);
}else{
intj=0;
for(j=1;comm[j][0]!
='\0';j++){
printf("%s",comm[j]);
printf("");
}
printf("\n");
}
}else{
intstatus;
wait(&status);
}
}elseif(strcmp(comm[0],"ls")==0){
intpid=fork();
if(pid==0){
if(comm[1][0]=='\0'){
execlp("/bin/ls","ls","./",NULL,NULL,NULL);
}else{
execlp("/bin/ls","ls",comm[1],NULL,NULL,NULL);
}
}else{
intstatus;
wait(&status);
}
}elseif(strcmp(comm[0],"cd")==0){
intpid=fork();
if(pid==0){
chdir(comm[1]);
}else{
intstatus;
wait(&status);
}
}elseif(strcmp(comm[0],"pwd")==0){
intpid=fork();
if(pid==0){
system("pwd");
}else{
intstatus;
wait(&status);
}
}elseif(strcmp(comm[0],"exit")==0){
return-1;
}
return1;
}
intmain()
{
while
(1){
charcommand[LEN];
charsplitArray[HEIGHT][WIDTH]={{'\0'}};
printf("%s",">>");
gets(command);
split(command,splitArray);
inti=0;
if(-1==execute(splitArray)){
return0;
}
}
}
:
实现shell程序,要求在第2版的基础上,添加如下功能
实现管道
$cat/etc/passwd|wc-l
实现管道和文件重定向
$cat
3
2
1
3
2
1
$cat<|sort|uniq|cat>
$cat
1
2
3
思路:
首先读取用户输入,以“|”为分隔符将输入分割成字符串数组,然后在一个while循环中依次执行下面的动作:
代码中通过pipe()函数来创建管道,创建之后父进程和子进程一个只能向管道写内容,一个只能向管道读内容。
然后利用dup()函数来把进程的输入流或者输出流重定向到管道里,这样就能实现管道的操作。
实现的时候注意可以使用多个“|”来迭代进行管道操作,需要使用一个循环来处理。
用system执行每一条命令,同时还要注意最后一个操作的输出流是标准输出(即屏幕),不需要重定向到管道里,需要特殊处理一下。
源代码:
#include<>
#include<>
#include<>
#include<>
#include
#include
#include<>
#defineLEN256
#defineWIDTH256
#defineHEIGHT10
voidsplit(charsource[],chardest[HEIGHT][WIDTH])
{
char*p;
p=strsep(&source,"|");
inti=0;
for(i=0;p[i]!
='\0';i++){
dest[0][i]=p[i];
}
dest[0][i]='\0';
intj=1;
while(p){
p=strsep(&source,"|");
if(p){
for(i=0;p[i]!
='\0';i++){
dest[j][i]=p[i];
}
dest[j][i]='\0';
j++;
}
}
}
main(){
charcommand[LEN];
charsplitArray[HEIGHT][WIDTH]={{'\0'}};
printf("%s",">>");
gets(command);
split(command,splitArray);
inti=0;
for(i=0;splitArray[i][0]!
='\0';i++){
puts(splitArray[i]);
}
intp[2];
pipe(p);
intj=0;
for(j=0;splitArray[j+1][0]!
='\0';j++){
if(fork()==0){
.=PI/4
主线程创建1个辅助线程
主线程计算级数的前半部分
辅助线程计算级数的后半部分
主线程等待辅助线程运行結束后,将前半部分和后半部分相加
思路:
计算公式前1000项,主线程计算前5000项,子线程计算后5000项,主进程等待子进程结束,通过pthread_join(sub,(void**)&result);的result参数获取子进程计算结果再相加即可。
源代码:
#include<>
#include<>
#include<>
#include<>
#defineLEN10000
structresult{
floatsum;
};
void*subThread(){
inti;
floatj;
structresult*result;
floatsum1=0,sum2=0,sum=0;
for(i=LEN/2+1;i<=LEN;i++){
j=i;
if(i%2==0){
sum1+=1/(2*j-1);
}
tart=0;
myparams[0].end=0;
for(i=1;i<=thread_num-1;i++){
structparam*myparam;
myparam=&myparams[i];
myparam->start=myparams[i-1].end+1;
myparam->end=myparams[i].start+(LEN/thread_num)-1;
pthread_create(&workers[i-1],NULL,compute,myparam);
}
myparams[thread_num].start=myparams[thread_num-1].end+1;
myparams[thread_num].end=LEN;
pthread_create(&workers[thread_num-1],NULL,compute,&myparams[thread_num]);
intj;
floatsum=0;
for(j=0;jstructresult*myresult;
pthread_join(workers[j],(void**)&myresult);
sum+=myresult->sum;
free(myresult);
}
printf("%f\n",sum);
return0;
}
:
多线程排序
主线程创建一个辅助线程
主线程使用选择排序算法对数组的前半部分排序
辅助线程使用选择排序算法对数组的后半部分排序
主线程等待辅助线程运行結束后,使用归并排序算法归并数组的前半部分和后半部分
思路:
主线程排序数组的前半部分,辅助线程排序后半部分,pthread_create(&worker_id,NULL,&sort,&pa);中pa传递的是数组的首地址,主线程等辅助线程结束后,再调用merge将数组合并为有序。
源代码:
#include<>
#include<>
#include<>
#include<>
#defineLEN10
intarray[LEN]={0,3,8,6,2,9,5,4,1,7};
structparam{
int*arr;
};
void*sort(void*arg){
structparam*mypa;
mypa=(structparam*)arg;
inti=0;
intj=0;
intmin=0;
inttemp=0;
for(i=LEN/2;imin=i;
for(j=i;jif(mypa->arr[min]>mypa->arr[j])min=j;
}
temp=mypa->arr[min];
mypa->arr[min]=mypa->arr[i];
mypa->arr[i]=temp;
}
}
voidmerge(){
inti=0;
inta[LEN/2];
intb[LEN/2];
for(i=0;ia[i]=array[i];
b[i]=array[i+LEN/2];
}
/*for(i=0;iprintf("%d\n",a[i]);
}*/
inttm=0;
intti=0,tj=0;
while(tiif(a[ti]
array[tm]=a[ti];
ti++;
}else{
array[tm]=b[tj];
tj++;
}
tm++;
}
}
intmain()
{
structparampa;
=array;
intti=0,tj=0,tmin=0;
for(ti=0;titmin=ti;
for(tj=ti;tjif(array[tmin]>array[tj])tmin=tj;
}
inttemp=array[tmin];
array[tmin]=array[ti];
array[ti]=temp;
}
pthread_tworker_id;
pthread_create(&worker_id,NULL,&sort,&pa);
pthread_join(worker_id,NULL);
merge();
inti=0;
for(i=0;iprintf("%d\n",array[i]);
}
}
:
使用条件变量解决生产者、计算者、消费者问题
系统中有3个线程:
生产者、计算者、消费者
系统中有2个容量为4的缓冲区:
buffer1、buffer2
生产者生产'a'、'b'、'c'、‘d'、'e'、'f'、'g'、'h'八个字符,放入到buffer1
计算者从buffer1取出字符,将小写字符转换为大写字符,放入到buffer2
消费者从buffer2取出字符,将其打印到屏幕上
思路:
类似于生产者和消费者,在问题中,生产者、计算者相对应buffer1是生产者、消费者,二者互斥的进入buffer1,并且当buffer1满时,生产者等待,当buffer1空时,且计算值要从中取数据时,计算者等待。
同理,计算者、消费者相对应buffer2是生产者和消费者,二者互斥的进入buffer2,当buffer2满时,且计算者要向其中放入数据时,计算者应等待,当buffer2空时,消费者应等待。
源代码:
#include<>
#include<>
#defineCAPACITY4
intbuffer1[CAPACITY];
intbuffer2[CAPACITY];
intin1;
intout1;
intin2;
intout2;
intbuffer2_is_empty()
{
returnin2==out2;
}
intbuffer2_is_full()
{
return(in2+1)%CAPACITY==out2;
}
intbuffer1_is_empty()
{
returnin1==out1;
}
intbuffer1_is_full()
{
return(in1+1)%CAPACITY==out1;
}
intget_item()
{
intitem;
item=buffer2[out2];
out2=(out2+1)%CAPACITY;
returnitem;
}
voidput_item(intitem)
{
buffer1[in1]=item;
in1=(in1+1)%CAPACITY;
}
intcal_get_item()
{
intitem;
item=buffer1[out1];
out1=(out1+1)%CAPACITY;
returnitem;
}
voidcal_put_item(intitem)
{
buffer2[in2]=item;
in2=(in2+1)%CAPACITY;
}
pthread_mutex_tmutex1;
pthread_cond_twait_empty_buffer1;
pthread_cond_twait_full_buffer1;
pthread_mutex_tmutex2;
pthread_cond_twait_empty_buffer2;
pthread_cond_twait_full_buffer2;
#defineITEM_COUNT(CAPACITY*2)
void*consume(void*arg)
{
inti;
intitem;
for(i=0;ipthread_mutex_lock(&mutex2);
while(buffer2_is_empty())
pthread_cond_wait(
&wait_full_buffer2,
&mutex2);
item=get_item();
printf("consumeitem:
%c\n",item);
sleep
(1);
pthread_cond_signal(&wait_empty_buffer2);
pthread_mutex_unlock(&mutex2);
}
returnNULL;
}
void*calculate(void*arg)
{
inti;
intitem;
for(i=0;ipthread_mutex_lock(&mutex1);
while(buffer1_is_empty())
pthread_cond_wait(
&wait_full_buffer1,
&mutex1);
item=cal_get_item();
item+='A'-'a';
pthread_cond_signal(&wait_empty_buffer1);
pthread_mutex_unlock(&mutex1);
pthread_mutex_lock(&mutex2);
while(buffer2_is_full())
pthread_cond_wait(&wait_empty_buffer2,&mutex2);
cal_put_item(item);
pthread_cond_signal(&wait_full_buffer2);
pthread_mutex_unlock(&mutex2);
}
returnNULL;
}
voidproduce()
{
inti;
intitem;
for(i=0;ipthread_mutex_lock(&mutex1);
while(buffer1_is_full())
pthread_cond_wait(&wait_empty_buffer1,&mutex1);
item=i+'a';
printf("produceitem:
%c\n",item);
put_item(item);
sleep
(1);
pthread_cond_signal(&wait_full_buffer1);
pthread_mutex_unlock(&mutex1);
}
}
intmain()
{
pthread_tconsumer_tid;
pthread_tcalculate_tid;
pthread_mutex_init(&mutex1,NULL);
pthread_cond_init(&wait_empty_buffer1,NULL);
pthread_cond_init(&wait_full_buffer1,NULL);
pthread_mutex_init(&mutex2,NULL);
pthread_cond_init(&wait_empty_buffer2,NULL);
pthread_cond_init(&wait_full_buffer2,NULL);
pthread_create(&calculate_tid,NULL,calculate,NULL);
pthread_create(&consumer_tid,NULL,consume,NULL);
produce();
return0;
}
:
使用信号量解决生产者、计算者、消费者问题
功能和前面的实验相同,使用信号量解决
思路:
类似于
源代码:
#include<>
#include<>
#i