操作系统设计大实验

1、设自行车生产线上有一只箱子,其中有N个位置(N≥3),每个位置可存放一个车架或一个车轮,又设有三名工人,其活动分别为:
在这里插入图片描述
用信号量PV操作编程实现三个工人的合作,不能出现死锁。要求N的大小可自定义,显示自行车生产组装的过程。(25分)
解:
分析:根据题目意义分析,该题所述作业工人1、工人2与工人3构成生产者与消费者关系,存在着生产者-消费者问题的同步关系,涉及的知识点包括:信号量、PV原语、进程同步、死锁问题等。
解决思路:先不考虑死锁问题,工人1、2分别与3是生产者和消费者关系。箱子内的空位是工人1、2的资源,车架和车轮是工人3的资源。定义三个信号灯如下:

semaphore empty=N;//箱子内的空位
semaphore weel=0;//车轮
semaphore frame=0;//车架

再来看死锁问题:如果说工人1或者工人2某一方生产速度很快,N个空位全部为车轮,或者≥N-1个空位是车架的话(此时最多只能放入一个车轮),工人3永远得不到组装一个完整的车的资源,就会发生死锁。所以车架最多不能达到N-2个,也就是车架的信号量初值要设置为N-2,车轮要设置为N-1。
伪代码如下:

semaphore empty = N;//空位置数量
semaphore maxframe = N-2;//箱中最大车架数量
semaphore maxwheel = N-1;//箱中最大车轮数量
semaphore frame = 0;//车架数量
semaphore wheel = 0;//车轮数量
do{ //工人1活动P(maxframe);
P(empty);
加工一个车架;
车架放入箱中;
V(frame);
}while(1)do{ //工人2活动P(maxwheel);
P(empty);
加工一个车轮;
车轮放入箱中;
V(wheel);
}while(1)do{ //工人3活动
P(frame);
P(wheel);
P(wheel);
箱中取一个车架;
箱中取一个车架;
组装一台车;
V(maxframe);
V(maxwheel);
V(maxwheel);
V(empty);
V(empty);
V(empty);
}while(1)

源代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>
sem_t empty;//箱子内的空位
sem_t wheel;//车轮
sem_t frame;//车架
sem_t s1;//车架最大值
sem_t s2;//车轮最大值
pthread_t worker1_thread, worker2_thread, worker3_thread;//声明三个工人的线程
void * worker1Thread(void *i)
{while(1){	sleep(2);//工人1生产一个车架printf("worker1 products a frame!\n");sem_wait(&empty);sem_wait(&s1);	sleep(1);//工人1将车架放入箱子printf("worker1 places a frame in the box!\n");sem_post(&frame);}
}
void * worker2Thread(void *i)
{while(1){	
sleep(1);//工人2生产一个车轮
printf("worker2 products a wheel!\n");sem_wait(&empty);sem_wait(&s2);	sleep(1);//工人2将车轮放入箱子printf("worker2 places a wheel in the box!\n");sem_post(&wheel);}
}
void * worker3Thread(void *i)
{while(1){	sem_wait(&frame);sleep(1);//工人3从箱子中拿一个车架printf("worker3 takes out a frame from the box!\n");sem_post(&empty);	sem_post(&s1);sem_wait(&wheel);sem_wait(&wheel);sleep(2);//工人3从箱子中拿两个车轮printf("worker3 takes out two wheels from the box!\n");sem_post(&empty);sem_post(&empty);sem_post(&s2);sem_post(&s2);
sleep(3);//工人3生产一辆自行车printf("worker3 products a bicycle!\n");}
}
int main(){int N;printf("Please enter the number of the box positions:");scanf("%d",&N);printf("\n");//初始化信号量sem_init(&empty, 1, N);sem_init(&wheel, 1, 0);sem_init(&frame, 1, 0);sem_init(&s1, 1, N-2);sem_init(&s2, 1, N-1);int ret;char taskNum;printf("input 'q' to exit!\n");ret=pthread_create(&worker1_thread,NULL,worker1Thread,NULL);if(ret!=0){printf("Create thread1 error\n");exit(1);}ret=pthread_create(&worker2_thread,NULL,worker2Thread,NULL);if(ret!=0){printf("Create thread2 error\n");exit(1);}ret=pthread_create(&worker3_thread,NULL,worker3Thread,NULL);if(ret!=0){printf("Create thread3 error\n");exit(1);}while (scanf("%c", &taskNum) != EOF) {if (taskNum == 'q') {break;}}sem_destroy(&empty);sem_destroy(&frame);sem_destroy(&wheel);sem_destroy(&s1);sem_destroy(&s2);return 0;
}

编译链接:

gcc ceshi1.c -o ceshi1

在这里插入图片描述
运行:
./ceshi1
运行结果示意图:
在这里插入图片描述
在这里插入图片描述
2、编写一个用于检查关于命令“ls px ct"的实验报告的Shell脚本,该脚本检查命令的执行结果中是否存在包含“px”和“ct”的文件或目录,显示包含“px”的文件或目录数,包含“ct”的文件或目录数。如果两者的文件或目录数均大于0,则对该实验项目给予100分。如果其中之一的文件或目录数为0,则对该实验项目给予50分,如果两者的文件或目录数均为0,则对该实验项目给予0分。(25分)
解:
源代码:

#!/bin/bash
#统计文件个数 
file_count1=0 
file_count2=0 
#查看所有目录
file_list=`ls *px* *ct*` 
#输出所有符合要求的文件名以及目录名
for file_name in $file_list 
do echo $file_name
done 
#计数名称包括*px*的文件或目录数
file_list=`ls *px*` 
for file_name in $file_list 
do let file_count1++
done 
#计数名称包括*ct*的文件或目录数
file_list=`ls *ct*` 
for file_name in $file_list 
do let file_count2++
done 
#分别输出两种的文件或目录数
echo -e "\n-------------------------------------------------" 
echo -e "\n\n*px*Total: $file_count1" 
echo -e "*ct*Total: $file_count2" 
echo -e "\nFind Finished!\n"

运行:
. ./ceshi2.sh
运行结果:
在这里插入图片描述
3、编写套接字通信程序,实现简单的文字发送、接收形式的会议功能。主持人运行服务器程序,参会者运行客户端程序。主持人发送的文字信息每个客户端用户都可以看到。任一客户端用户发送的文字信息包括主持人在内的其他参会者也都可以看到。服务器或者客户端显示当前开会人数,参会者标识,以及当前发送信息的程序或者用户的标识。(50分)
解:
源程序:


```c
服务器程序ceshi3Server.c:
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <arpa/inet.h>
#include <string.h> 
#include <pthread.h> 
#include <semaphore.h> 
#define LinkNum 5			//连接数
int client_sockfd[LinkNum];		/*分别记录服务器端的套接字与连接的多个客户端的套接字*/
int server_sockfd = -1;		//命名套接字
int curLink=0;				//当前连接数
sem_t mutex;				//表示连接数的资源信号量
char stopmsg[1024];			//服务器端发送消息缓冲区
void quit()//客户服务通信结束处理函数
{int i;char mm[] = "会议结束!请输入'!q'退出会议!";char msg[1024];char s4[] = "主持人发言:";int f1=0,f2=0,f3=0;while(1){memset(stopmsg, 0, 1024);        for(f1=0,f2=0;f1<sizeof(s4)-1&f2<sizeof(msg);f1++,f2++)msg[f2]=s4[f1];memset(stopmsg, 0, 1024);scanf("%s",stopmsg);for(f3=0;f3<sizeof(stopmsg)-1&f2<sizeof(msg);f3++,f2++)msg[f2]=stopmsg[f3];if(strcmp(stopmsg,"quit")==0){//如果服务器端发送消息为"quit",则提示服务器将关闭printf("结束会议!\n");for(i=0;i<LinkNum;i++)if(client_sockfd[i]!=-1){write(client_sockfd[i], msg, sizeof(msg));write(client_sockfd[i], mm, sizeof(mm));}/*依次向继续保持连接的客户端发出“会议结束”的通知消息*/close(server_sockfd);	//关闭服务器监听套接字sem_destroy(&mutex);	//销毁连接数资源信号量mutexexit(0);}else{for(i=0;i<LinkNum;i++)if(client_sockfd[i]!=-1)write(client_sockfd[i], msg, sizeof(msg));}}
}
void rcv_snd(int n)//服务器与客户端的收发通信函数,n为连接数组序号
{int i=0;int retval;char recv_buf[1024]; 	//接收消息缓冲区char send_buf[1024]; 	//发送消息缓冲区int client_len = 0;int rcv_num;		//从客户端接收到的消息长度pthread_t tid;  		//线程idtid = pthread_self();	//获取当前线程idchar c = n +'0'+1;char s[] = "您的用户标识是:";s[sizeof (s) - 1] = c;write(client_sockfd[n], s, sizeof(s));do//服务器与客户端循环发送接收消息{memset(recv_buf, 0, 1024);//接收消息缓冲区清零rcv_num = read(client_sockfd[n], recv_buf,sizeof(recv_buf));printf("%d发言:(%d) :%s\n",n+1,rcv_num, recv_buf );if(rcv_num==0)  break;if(strncmp(recv_buf,"!q",2)==0)  break;	//若接收到"!q",则结束循环,通信结束else{char s3[] = "n发言:";s3[0]=c;memset(send_buf, 0, 1024);int f1=0,f2=0,f3=0;for(;f1<sizeof(s3)-1&f2<sizeof(send_buf);f1++,f2++)send_buf[f2]=s3[f1];for(;f3<sizeof(recv_buf)&f2<sizeof(send_buf);f3++,f2++)send_buf[f2]=recv_buf[f3];for(int i=0;i<LinkNum;i++)if(client_sockfd[i]!=-1)write(client_sockfd[i], send_buf, sizeof(send_buf));}}while(strncmp(recv_buf,"!q",2)!=0);printf("%d号发言人退出会议!\n",n+1);close(client_sockfd[n]);		//关闭连接套接字client_sockfd[n]=-1; 		//被关闭连接套接字数组项置为空闲curLink--;				//当前连接数减1printf("当前开会人数为:%d(<=%d)\n",curLink,LinkNum);		//输出当前连接数和最大连接数char s1 = curLink + '0';char s2[] = "有1人退出会议,当前开会人数为:";s2 [sizeof (s2) - 1] = s1;for(int i=0;i<LinkNum;i++)if(client_sockfd[i]!=-1)write(client_sockfd[i], s2, sizeof(s2));sem_post(&mutex);			//释放可用连接数资源信号量mutexpthread_exit(&retval);		//当前服务器线程结束
}
int main(void)
{char recv_buf[1024];			//接收消息缓冲区char send_buf[1024]; 			//发送消息缓冲区int client_len = 0;struct sockaddr_in server_addr;	//服务器端协议地址struct sockaddr_in client_addr; 	//客户端协议地址int i=0;				//连接套接字数组循环变量pthread_t thread;server_sockfd = socket(AF_INET, SOCK_STREAM, 0);server_addr.sin_family = AF_INET;	//指定网络套接字server_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//接受所有IP地址的连接server_addr.sin_port = htons(9736);		//绑定到9736端口bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));//协议套接字命名为server_sockfdprintf("会议开始...\n");listen(server_sockfd, LinkNum);	/*创建连接数最大为LinkNum的套接字队列,监听命名套接字,listen不会阻塞,它向内核报告套接字和最大连接数*/signal(SIGCHLD, SIG_IGN); 	//忽略子进程停止或退出信号printf("输入quit,会议结束.\n");//输入quit,服务结束printf("您的用户标识是主持人!\n");pthread_create(&thread,NULL,(void*)(&quit),NULL);//创建线程,执行函数quitfor(i=0;i<LinkNum;i++)  client_sockfd[i]=-1;//初始化连接队列sem_init(&mutex,0,LinkNum);	//信号量mutex初始化为连接数while(1){for(i=0;i<LinkNum;i++)		//搜寻空闲连接if(client_sockfd[i]==-1) break;if(i==LinkNum){//如果达到最大连接数,则客户等待printf("会议人数已达上限%d,请等待其它用户退出...\n",LinkNum);sem_wait(&mutex);		//阻塞等待空闲连接continue;			//被唤醒后继续监测是否有空闲连接}client_len = sizeof(client_addr);client_sockfd[i] = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len);printf("%d号用户进入会议\n",i+1);curLink++;				//当前连接数增1sem_wait(&mutex);			//可用连接数信号量mutex减1printf("当前会议人数为:%d(<=%d)\n",curLink,LinkNum);char c1 = i +'0' +1;char c2 = curLink +'0' +1;char c3[] = "n号用户进入会议,当前会议人数为:";c3 [sizeof (c3) - 1] = c2;c3[0] = c1;for(int i=0;i<LinkNum;i++)if(client_sockfd[i]!=-1)write(client_sockfd[i], c3, sizeof(c3));pthread_create(malloc(sizeof(pthread_t)),NULL,(void*)(&rcv_snd),(void*)i);}
}
客户端程序ceshi3Client.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
struct mypara
{int para1;//参数1int para2;//参数2
};
void get(void* arg)//客户
{char rcv_buf[1024]; 		//接收消息缓冲区int rcv_num;struct mypara *parat;parat = (struct mypara*)arg;int sockfd = (*parat).para2;int cpid = (*parat).para1;do{memset(rcv_buf, 0, 1024);		//接收缓冲区清零            rcv_num = read(sockfd, rcv_buf, sizeof(rcv_buf));if(rcv_num==0)continue;printf("%s\n",rcv_buf);	//输出客户机从服务器接收的消息;          if(strncmp(rcv_buf,"quit",4)==0) break;	//如果收到"quit",则结束循环,通信结束}while(strncmp(rcv_buf,"!q",2)!=0); //如果收到"!q",则结束循环,通信结束printf("会议结束!\n");close(sockfd);
}
int main(void)
{int sockfd;				//客户端套接字描述符int len = 0;struct sockaddr_in address;	//套接字协议地址char rcv_buf[1024]; 		//接收消息缓冲区int result;int rcv_num;				//接收消息长度pid_t cpid;				//客户进程标识符pthread_t thread1;sockfd = socket(AF_INET, SOCK_STREAM, 0);	if(sockfd < 0){perror("进入会议失败!\n");return 1;}address.sin_family = AF_INET;	//使用网络套接字address.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器地址address.sin_port = htons(9736);	//服务器所监听的端口if(inet_aton("127.0.0.1",&address.sin_addr)<0){printf("inet_aton error.\n");return -1;}len = sizeof(address);cpid=getpid();			//获取客户进程标识符result = connect(sockfd, (struct sockaddr*)&address, len);if(result == -1){perror("进入会议失败!\n");exit(1);}struct mypara para;para.para1=cpid;para.para2=sockfd;printf("输入!q,退出会议.\n");//输入quit,服务结束pthread_create(&thread1,NULL,(void*)(&get),&(para));char send_buf[1024]; 		//发送消息缓冲区while(1){//客户机与服务器循环发送接收消息memset(send_buf, 0, 1024);		//发送缓冲区清零scanf("%s",send_buf);	//键盘输入欲发送给服务器的消息字符串write(sockfd, send_buf, sizeof(send_buf));	//将消息发送到套接字if(strncmp(send_buf,"!q",2)==0) break;//若发送"!q",则结束循环,通信结束}printf("您退出会议!\n");close(sockfd);		//关闭客户机套接字
}

编译链接命令:

gcc ceshi3Server.c -o ceshi3Server -lpthread
gcc ceshi3Client.c -o ceshi3Client

运行命令:

./test3Server
./test3Client

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/428041.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ZigBee学习——浅析协议栈

✨记录学习过程 文章目录 一、初识OSAL1.1 Z-Stack和Zigbee的OSAL是什么关系&#xff1f;1.2 OSAL可以解决Z-stack在不同厂商的芯片上的使用吗&#xff1f; 二、协议栈运行机制2.1 初始化涉及内容2.2 初始化过程 一、初识OSAL OSAL&#xff0c;全称是操作系统抽象层&#xff0…

【Vue3】计算属性computed和监听属性watch

目录 一、Vue3和Vue2的区别 二、计算属性computed 三、监听属性watch 四、计算属性和监听属性的区别 一、Vue3和Vue2的区别 Vue3和Vue2有以下几个主要区别&#xff1a; 响应式系统的改进&#xff1a;Vue3采用了Proxy作为响应式系统的核心&#xff0c;相比Vue2的Object.def…

vue打包后与本地测试样式不同问题,element-ui样式打包部署前后样式不同。

个别文件的样式中<style>未加scope。 查找到一些文件中修改了对应页面的elementUI的样式&#xff0c;但未加scope 给<style>加上scope&#xff0c;就好了。

河北移动与中兴通讯现已规模部署5G AAU自动启停功能

河北移动为积极响应国家战略&#xff0c;践行中国移动双碳行动计划&#xff0c;致力联合产业合作伙伴多次探索能耗更低的节电新模式。最近&#xff0c;河北移动就与中兴通讯完成了5G AAU自动启停功能的研发以及规模商用部署&#xff0c;成功打造出5G网络绿色节能低碳运营新范式…

Tween.js 使用文档 --- Three.js

Tween.js官网文档&#xff1a;tween.js user guide | tween.js (tweenjs.github.io) Tween.js 基本使用 1. 引入Tween.js import TWEEN from "./tween.js-master/dist/tween.esm.js" 2. 定义基本Tween动画 目的&#xff1a;将model模型的位置&#xff0c;从原来的(0…

杰卡德距离(Jaccard Distance)

杰卡德距离&#xff08;Jaccard Distance&#xff09;&#xff0c;是用于衡量两个集合差异性的一种指标&#xff0c;它是杰卡德相似系数的补集&#xff0c;可以用来区分集合&#xff08;如知识图谱&#xff09;。 杰卡德相似系数 杰卡德相似系数&#xff08;Jaccard similari…

橘子学Mybatis08之Mybatis关于一级缓存的使用和适配器设计模式

前面我们说了mybatis的缓存设计体系&#xff0c;这里我们来正式看一下这玩意到底是咋个用法。 首先我们是知道的&#xff0c;Mybatis中存在两级缓存。分别是一级缓存(会话级)&#xff0c;和二级缓存(全局级)。 下面我们就来看看这两级缓存。 一、准备工作 1、准备数据库 在此之…

深度学习在物理层信号处理中的应用研究

随着移动流量呈现的爆发式增长、高可靠性和低时延的通信场景给当前网络带来了更大的复杂性和计算挑战。据IBM报道&#xff0c;移动数据量到2020年将超过40万亿Gbits&#xff0c;比2009年增加44倍&#xff0c;连接总设备量将达到500亿。为了满足这一需求&#xff0c;需要新的通信…

云卷云舒:PostgreSQL的事儿你听说了吗?

最近&#xff0c;PostgreSQL公布了全球贡献者名单。 以上是全球贡献者主要成员&#xff0c;可以看出都是外国人&#xff0c;除了一名台湾省贡献者外&#xff0c;几乎再看不到中国贡献者的身影。 那么偌大的中国&#xff0c;为什么在PostgreSQL的全球贡献者名单里面就看不到人呢…

【GitHub项目推荐--一款美观的开源社区系统】【转载】

推荐一款开源社区系统&#xff0c;该系统基于主流的 Java Web 技术栈&#xff0c;如果你是一名 Java 新手掌握了基本 JavaEE 框架知识&#xff0c;可以拿本项目作为练手项目。 开源社区系统功能还算完善包含发布帖子、发布评论、私信、系统通知、点赞、关注、搜索、用户设置、…

遇到DNS劫持怎么办

什么是DNS劫持&#xff1f; DNS劫持又称域名劫持&#xff0c;是攻击者利用缺陷对用户的DNS进行篡改&#xff0c;将域名由正常IP指向攻击者控制的IP&#xff0c;从而导致访客被劫持到一个不可达或者假冒的网站&#xff0c;以此达到非法窃取用户信息或者破坏正常网络服务的目的。…

一个使用pyqt的word文档查重工具

一个使用pyqt的word文档查重工具 使用场景代码使用截图打包好的软件下载链接结尾 使用场景 有时我们在借鉴一篇文档之后还不想有太多重复&#xff0c;这个时候可以使用这个工具对两个word文档进行对比 代码 import sys from PyQt5.QtWidgets import QApplication, QMainWind…