第一篇:利用整型信号量解决理发师问题[定稿]
利用整型信号量解决理发师问题
int waiting=0;//等候理发的人数,临界资源
semaphore customers=0,barbers=0;//两个信号量,顾客和理发师
semaphore mutex=1;//此信号量是为操作临界资源waiting而设的barber()//理发师进程
{
While(1)
{
}
}
customer()//顾客进程
{
P(mutex);//开始操作临界资源
if(waiting { } waiting++;//等候的人数加1 V(customers);//来了一个顾客 V(mutex);//开放临界资源 P(barbers);//等理发师来理发,之后表明理发师忙碌 顾客接受理发师理发();P(customers);//是否有顾客,若没有则理发师睡觉 P(mutex);//当有顾客时,执行此语句,开始操作临界资源waiting waiting--;//等候的人数减1 V(barbers);//表明理发师空闲,可以理发了 V(mutex);//开放临界资源 理发师为顾客理发(); else//若没有空座,直接走人,并开放临界资源 V(mutex); } 利用整型信号量解决和尚打水问题 semaphore mutex1=1,mutex2=1;//分别为操作“井”和“水缸”这两个临界资源的信号量 semaphore count=3;//操作临界资源“水桶”的信号量,表明可用水桶的数目 semaphore empty=10,full=0;//水缸满和空的信号量 young()//小和尚进程 { while(1) { P(empty);//判断水缸是否可装水 P(count);//是否有可用的水桶,申请使用一个水桶 P(mutex1);//操作临界资源“井” 小和尚从井中取水(); } V(mutex1);//开放“井” P(mutex2);//操作临界资源“水缸” 小和尚把水倒入水缸();V(mutex2);//开放“水缸” V(count);//归还一个水桶 V(full);//表明水缸中已经添加了一桶水 } old()//老和尚进程 { while(1) { } } P(full);//判断水缸中是否有水可喝 P(mutex2);//操作临界资源“水缸” 老和尚从水缸中取水();V(mutex2);//开放“水缸” V(empty);//表明水已经被喝了一桶 利用尾注和交叉引用解决参考文献问题 参考文献是学位论文中繁琐复杂的部分,如果处理不好会耽误很多时间。在WORD中较好的解决方式是利用尾注和交叉引用。这样可以自动排号。但是,直接用尾注编参考文献存在一些问题,应该相应采用一些技巧: 参考文献的插入:选择“插入——引用——脚注和尾注”。出现尾注插入对话框,位置设置为尾注,文档结尾;编号格式选1,2,3….,然后插入。在文档结尾编写参考文献条目。 尾注上方的短线需要去掉。选“视图——普通”;再选“视图——脚注”;在下面出现的脚注部分下拉菜单选“尾注分隔符”将出现的短线删除;再选“尾注延续分隔符”,将出现的直线也删除。 尾注的数字为上标格式,可选中通过快捷键“Ctrl+Shift+=”将编码数字改为非上标。然后选中参考文献条目,选“格式——段落”,设置为悬挂缩进(约0.74厘米)。 参考文献的交叉引用:前面已经插入的参考文献,文章后面再次引用时,通过交叉引用插入。方式为:“插入——引用——交叉引用”在对话框中选引用类型为“尾注”,选择要引用的条目插入即可。 这样可以完成参考文献的插入和引用。但是如出现连续引用的情况例如“[1-5]”时,则以上简单应用无法很好解决。而且论文中的引文标号分为首次插入标号和交叉引用标号两种,如果后续编辑中对论文某些部分删除了,如删除了首次插入的参考文献标号,则该尾注条目同时被删除,后面引用该文献的交叉引用项将会出现错误。 为了解决以上两个问题,可利用隐藏字体的方式。将所有首次插入的文献都放在正文之前,如目录后面,引文可以按章节分开。对引文用简单的名字表示,如:“Chen05[1]”表示作者为Chen于05年发表的文章。在论文中应用参考文献,均采用交叉引用的方式插入。这样对正文的删除编辑不会影响其他部分。调整前面插入尾注的前后顺序便可自动调节文中的因为编号。对于[1-5]的情况也可解决了。为了方便检查,可以写为“[1-5][1,2,3,4,5]”,这里数字均为交叉引用方式插入。然后把后面的部分选中,点“右键——字体”,设为隐藏字体。这样调整编辑之后,还可以检查文献编号是否还依然连续。 在编辑之后文章中的参考文献变换可能会变化,要选中有变化的段落,点“右键——更新域”进行编号更新。 最后编辑完后,将正文前面的文献插入内容全选中,设置字体为隐藏。 在尾注后面是无法添加其他内容的,但是学位论文要求参考文献后面还要有一些附录内容。采用隐藏的方式这一点不难办到。 题目: 用多线程同步方法解决睡眠理发师问题(Sleeping-Barber Problem)初始条件: 1.操作系统:Linux 2.程序设计语言:C语言 3.设有一个理发师,5把椅子(另外还有一把理发椅),几把椅子可用连续存储单元。 要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求) 1.技术要求: 1)为每个理发师/顾客产生一个线程,设计正确的同步算法 2)每个顾客进入理发室后,即时显示“Entered” 及其线程自定义标识,还同时显示理发室共有几名顾客及其所坐的位置。3)至少有10个顾客,每人理发至少3秒钟。4)多个顾客须共享操作函数代码。 2. 设计说明书内容要求: 1)设计题目与要求 2)总的设计思想及系统平台、语言、工具等。3)数据结构与模块说明(功能与流程图) 4)给出用户名、源程序名、目标程序名和源程序及其运行结果。(要注明存储各个程序及其运行结果的主机IP地址和目录。) 5)运行结果与运行情况 (提示:(1)连续存储区可用数组实现。 (2)编译命令可用: cc-lpthread-o 目标文件名 源文件名(3)多线程编程方法参见附件。) 1设计题目与要求 1.1 设计题目 用多线程同步方法解决睡眠理发师问题(Sleeping-Barber Problem)1.2 设计要求 1.2.1 初始条件 (1)操作系统:Linux(2)程序设计语言:C语言 (3)设有一个理发师,5把椅子(另外还有一把理发椅),几把椅子可用连续存储单元。 1.2.2 技术要求 (1)为每个理发师/顾客产生一个线程,设计正确的同步算法 (2)每个顾客进入理发室后,即时显示“Entered” 及其线程自定义标识,还同时显示理发室共有几名顾客及其所坐的位置。(3)至少有10个顾客,每人理发至少3秒钟。(4)多个顾客须共享操作函数代码。总体设计思想及开发环境与工具 2.1 总体设计思想 题目中要求描述理发师和顾客的行为,因此需要两类线程barber()和customer()分别描述理发师和顾客的行为。其中,理发师有活动有理发和睡觉两个事件;等待和理发二个事件。店里有固定的椅子数,上面坐着等待的顾客,顾客在到来这个事件时,需判断有没有空闲的椅子,理发师决定要理发或睡觉时,也要判断椅子上有没有顾客。所以,顾客和理 发师之间的关系表现为: (1)理发师和顾客之间同步关系:当理发师睡觉时顾客近来需要唤醒理发师为其理发,当有顾客时理发师为其理发,没有的时候理发师睡觉。 (2)理发师和顾客之间互斥关系:由于每次理发师只能为一个人理发,且可供等侯的椅子有限只有n把,即理发师和椅子是临界资源,所以顾客之间是互斥的关系。(3)故引入3个信号量和一个控制变量: ⅰ控制变量waiting用来记录等候理发的顾客数,初值为0; ⅱ信号量customers用来记录等候理发的顾客数,并用作阻塞理发师进程,初值为0; ⅲ信号量barbers用来记录正在等候顾客的理发师数,并用作阻塞顾客进程,初值为1; ⅳ信号量mutex用于互斥,初值为1 2.2 多线程编程原理 此次在Linux下进行多线程编程需要用到pthread_create和pthread_join这两个函数。 2.2.1 创建一个线程 pthread_create用来创建一个线程,原型为: extern int pthread_create((pthread_t *__thread,__const pthread_attr_t *__attr,void *(*__start_routine)(void *), void *__arg))第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。函数thread不需要参数时,最后一个参数设为空指针。第二个参数设为空指针时,将生成默认属性的线程。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。 2.2.2 等待一个线程结束 pthread_join用来等待一个线程的结束,函数原型为: extern int pthread_join __P((pthread_t __th, void **__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存 储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被 等待的线程结束为止,当函数返回时,被等待线程的资源被收回。 2.2.3 信号量 (1)函数sem_init()用来初始化一个信号量,函数原型为: extern int sem_init __P((sem_t *__sem, int __pshared, unsigned int __value));sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。(2)函数sem_post(sem_t *sem)用来增加信号量的值。 当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。 (3)函数sem_wait(sem_t *sem)被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait(sem_t *sem)是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。 2.3 伪码实现 difine n 5; //为顾客准备的椅子数为5 semaphore mutex=1; //用于互斥 semaphore customers=0;//等候理发的顾客数 semaphore barbers=1;//正在等候顾客的理发师数 int waiting=0; //等候理发的顾客数 //理发师线程 void barber(){ while(true)//判断有无顾客 { wait(customers);//若无顾客,理发师睡眠 wait(mutex);//互斥 waiting--;//等候顾客数少一个 signal(mutex);//释放临界资源 signal(barber);//cut_hair;// } } //顾客线程 void customer(){ wait(mutex);// if(waiting 理发师去为一个顾客理发 正在理发 互斥 如果有空椅子,则等待 等候顾客数加1 释放临界资源 如果理发师睡觉,唤醒理发师理发师在理发, 顾客等候 顾客坐下等理发师 店里人满了,顾客离开 2.4 开发环境与工具 系统平台:LINUX环境 实现语言:C语言 开发工具:NANO编辑器 3数据结构与模块说明 3.1 数据结构 通过分析课程设计要求,定义以下的数据: sem_t mutex,customers,barbers;//design three semaphores: mutex,customer,barbers int waiting=0;//the number of waiting customers int chair[5];3.2程序模块说明 3.2.1主函数模块 主函数流程图如下: 3.2.2 理发师模块 理发师模块函数流程图如下: 3.2.3 顾客模块 顾客模块函数流程图如下: 源程序代码 #include #include //design three semaphores: mutex,customer,barbers sem_t mutex,customers,barbers;int waiting=0;//the number of waiting customers int chair[5];void * barber();void * customer(void *arg); int main(int argc,char *argv[]){ //create 10 semaphores and one Barber semaphore pthread_t Customer_id[10],Barber_id;int i;sem_init(&mutex,0,1);//init mutex semaphore to 1 sem_init(&customers,0,0);//init semaphore customers to 0 sem_init(&barbers,0,1); for(i=0;i<5;i++)pthread_create(&Barber_id,NULL,(void*)barber,NULL);for(i=0;i<10;i++)pthread_create(&Customer_id[i],NULL,(void*)customer,(void*)(i+1));for(i=0;i<10;i++)pthread_join(Customer_id[i],NULL);for(i=0;i<5;i++)pthread_join(Barber_id,NULL);return 0;} //creat barber pthread void * barber(){ int i;int next;//wait(customers),if no customers,barber sleeping sem_wait(&customers);sem_wait(&mutex);//wait(mutex)waiting--;//the numer of waiting reduce one for(i=0;i<5;i++){ if(chair[i]!=0){ next= chair[i];chair[i]=0;break;} } printf(“The barber is cutting %dth customer's hairn”,next);sleep(3);sem_post(&mutex);sem_post(&barbers);} //creat customer pthread void * customer(void *arg){ int i;sem_wait(&mutex);//wait(mutex)if(waiting if(waiting waiting++;//the numer of waiting plus one for(i=0;i<5;i++){ if(chair[i]==0){ chair[i]=(int)arg;break;} } printf(“***************************************************n”);printf(“Entered:Number %d customer comes,and sits at %d n”,(int)arg,(i+1));printf(“There are %d customer on the chairn”,waiting);printf(“The customers' location are:”);for(i=0;i<5;i++)printf(“%d ”,chair[i]);printf(“n”); sleep(1);sem_post(&mutex);//signal(mutex)sem_post(&customers);//signal(customers)sem_wait(&barbers);//wait(barbers)} else chair { printf(“Number %d comes,there are no chairs,the customer %d is leavingn”,(int)arg,(int)arg);sem_post(&mutex);} } 5.2.1 编辑,编译和运行的过程图 5.2.2 错误部分截图 5.2.3 正确运行结果图 第一次运行结果如下图: 第二次运行结果如下图: 第三次运行结果如下图; 6调试记录 6.1调试记录 周一因有培训与课设时间冲突,故没有上机操作,查阅了相关书籍,并在网上查找了相关资料,了解了linux多线程编程的原理,应注意的问题,及一些常用命令 周二先设计出了该程序的伪代码即其wait、signal操作。然后,根据其要求进行编程,由于使用的是多线程编程,开始进行编译的时候,编译命令输入错误,没有输入-lpthread,程序总是出现错误。同时,创建线程函数时,由于对其格式输入错误导致程序无法运行。例如sb.c,sb1.c等都为本次调试时的程序。 周三主要是不断的调试并完善程序。程序可以运行,但与要求总有些不符,故不断的进行修改,并对其输出的格式进行完善,使其输出看起来美观一些,容易观察一些。例如s.c,b.c等程序为此次调试结果。 周四主要是在原有代码的基础上,使程序更完整些。并进行结果的截图,开始设计并编写课程设计报告。 6.2自我评析和总结 通过本次编程我熟悉了linux 下的多线程编程和信号量实现wait、signal操作的全过程,对同步和互斥问题也有了更深一步的理解,同时,也使我对linux编程有了更多的了解,在很多方面,它与在windows下编程有着很大的不同,对与多线程来说更方便一些。 设计过程中也遇到不少困难,尤其是对于多线程的实现,结果总是不如想象中完美。比如其顾客编号的输出有时会不按顺序,输入有点乱。另外,有时,输出结束后,程序仍无法结束,必须强制性关闭终端才可以结束程序,这是本程序的一个不足之处。 在本次课程设计中我深深感觉到自己掌握的知识还远远不够,我明白光是知道书本上的知识是远远不够的,一定要把理论知识和实践结合起来。同时,要多多学习linux的操作。 利用导数解决生活中的优化问题 本节是用导数的知识解决实际生活中的一些问题,这些问题运用导数的知识解决非常方便.例如,在生活、生产和科研中经常遇到的成本最低、用料最省、效率最高、利润最大等问题,这些问题统称为优化问题.一、利用导数解决优化问题,往往归结为求函数的最大值或最小值问题.二、利用导数解决实际问题中的优化问题时,要注意以下几点: 1.当问题中涉及多个变量时,应根据题意分析它们的关系,找出变量间的关系式; 2.确定函数关系式中自变量的取值范围; 3.所得的结果要符合问题的实际意义.三、要注意方法的灵活运用,如配方法、基本不等式法、导数法.例题:已知某商品生产成本C与产量q(0 8q,求产量q为何值时,利润L最大.一、用长为18 cm的钢条围成一个长方体形状的框架,要求长方体的长与宽 之比为2:1,问该长方体的长、宽、高各为多少时,其体积最大?最大体积是多少? 二、统计表明,某种型号的汽车在匀速行驶中每小时耗油量y(升)关于行驶速度x(千米/小时)的函数解析式可以表示为:y=1 128000x23 80x8(0 距100千米。 (Ⅰ)当汽车以40千米/小时的速度匀速行驶时,从甲地到乙地要耗油多少升?(Ⅱ)当汽车以多大的速度匀速行驶时,从甲地到乙地耗油最少?最少为多少升? 三、某商品每件成本9元,售价为30元,每星期卖出432件.如果降低价格,销售量可以增加,且每星期多卖出的商品件数与商品单价的降低值x(单位:元,0≤x≤30)的平方成正比.已知商品单价降低2元时,一星期多卖出24件. (I)将一个星期的商品销售利润表示成x的函数; (II)如何定价才能使一个星期的商品销售利润最大? 四、已知A、B两地相距200千米,一只船从A地逆水到B地,水速为8千米小时,船在静水中的速度为v千米小时(8<v≤v0).若船每小时的燃料费与其在静水中的速度的平方成正比,当v=12千米小时,每小时的燃料费为720元,为了使全程燃料费最省,船的实际速度为多少? 很多光盘内容复制到电脑上就不能使用,下面以教学光盘为例: 小学数学教师用书光盘DVD2,复制到电脑上后,1、单击开始图标 2、弹出右边提示框 为了解决这一问题,我们使用:UltraISO软碟通,它是一款功能强大而又方便实用的光盘映像文件制作/编辑/转换工具。 3、下载安装完成后,我的电脑里面也会多出一个驱动器: 4、打开软件: 5、此时打开光盘文件夹所在目录,全选,把所有文件拖到上面的方框里,6、单击文件,另存为,系统会自动保存为“.iso”文件。 7、回到工具主界面,工具,加载到虚拟光驱,8、单击映像文件后面的省略号按钮,选择第6步保存的“.iso”文件,单击加载,此时第3步的驱动器里面已经有光盘了。 9、双击打开,再点第1步的图标就可以了。第二篇:利用尾注和交叉引用解决参考文献问题
第三篇:操作系统课程设计--用多线程同步方法解决睡眠理发师问题(Sleeping-Barber_Problem)
第四篇:利用导数解决生活中的优化问题
第五篇:利用虚拟光驱解决“请在光驱中运行”问题