目 录
第1章 题目分析. 1
1.1 生产者线程... 1
1.2 消费者线程... 1
1.3 缓冲区... 1
1.4 进程的同步与互斥... 1
第2章 解决方案. 2
2.1 总体方案... 2
2.2 生产者问题... 2
2.3 消费者问题... 3
2.4 进程问题... 5
第3章 实验结果. 6
3.1 运行结果... 6
3.2 结果分析... 8
第4章 实验总结. 8
参考文献. 9
第1章 题目分析
在我的题目中,要求创建4个工厂同时生产一种商品,并由1个销售商进行销售。这是一个典型的生产者-消费者问题。经过查阅资料,我对这个问题有了一个初步的认识和分析。在uC/OS-II实时操作系统中,生产者-消费者问题是指多个任务之间共享一个有限缓冲区的情况下的同步与通信问题。生产者任务负责向缓冲区中放入数据,而消费者任务则负责从缓冲区中取出数据。这需要确保生产者和消费者之间的协调,避免生产者在缓冲区已满时继续生产,或者消费者在缓冲区为空时继续消费的问题。通过信号量来实现生产者与消费者之间的有效通信和同步。
1.1 生产者线程
生产者线程是在生产者消费者问题中负责向共享缓冲区中放入数据的线程。其主要任务是生成数据,并将数据放入缓冲区中。生产者线程需要注意缓冲区的状态,当缓冲区已满时需要等待,直到有空间可以放入新的数据。为了实现线程间的同步与通信,生产者线程可以使用信号量同步机制来控制对共享资源的访问。
1.2 消费者线程
消费者线程与生产者线程类似,是在生产者消费者问题中负责从共享缓冲区中取出数据的线程。主要作用是消耗数据,并将缓冲区中的数据取出,释放空间。消费者线程需要注意缓冲区的状态,当缓冲区为空时需要等待,直到有数据可供消费。与生产者线程相同,可以使用信号量同步。
1.3 缓冲区
缓冲区相当于仓库,是在生产者消费者问题中用于存储数据的区域。用来在生产者和消费者之间传递数据。生产者负责向缓冲池中写入数据,而消费者则从中读取数据进行处理。缓冲区位置的空和缺会影响生产者和消费者线程的行为。
1.4 进程的同步与互斥
为了使进程之间正确协调和共享资源,就需要进程的同步与互斥,进程的同步能够确保进程按照特定顺序执行,互斥则是确保在任何时刻只有一个进程可以访问共享资源,通过同步机制和互斥锁或信号量,确保进程间的安全交互和数据一致性。
在编写程序时,我创建了两个信号量,分别是mutex、empty、full、proCmutex。mutex用来控制对共享缓冲区的访问,初始值为1,此时表示共享资源可访问。也就是可以生产和销售产品。empty用来表示空闲的缓冲区空位的数量,初始值为缓冲区的大小,在我的实验中,这个值等于100。full用来表示已被生产者填充的缓冲区空位的数量,初始值为0,表示初始时没有产品可已消费。proCmutex用来控制生产者计数的访问,初始值为1,此时表示初始时生产者计数可以进行访问。
第2章 解决方案
2.1 总体方案
为了完成从生产到销售这一完整的产业链,需要完成并协调生产工厂、仓库、销售商三个主要部分的工作,实验的总体思路非常明确。首先是4个生产商同时进行商品的生产,然后把生产的东西放入库存,最后由1个销售商进行销售即可。
图2-1 总体系统方案
2.2 生产者问题
根据生产问题的逻辑关系,绘制图2-2的流程图。首先是生产系统的初始化,这里把商品的初始数量设置为0,然后开始生产商品,4个工厂一次同时生产1个商品,并将生产的商品放入缓冲区中,库存的最大数量是100,当生产的商品的数量大于100时,立即停止生产,并等待商品的销售;然后更新库存,再次判断库存的数量是否在合理范围内。
- void* producer(void* a) {
- while (true) {
- while (proCmutex <= 0);
- proCmutex--;
- proCount++;
- gc++;
- printf("[%d号] 工厂生产一个傻妞\n",gc);
- if (gc >= 4) { gc = 0; }
- full++;
- printf("当前库存数量:%d\n", full);
- proCmutex++;
- while (empty <= 0) {
- printf("库存已满!\n");
- Sleep(2000); }
- empty--;
- while (mutex <= 0);
- mutex--;
- buffer[in] = proCount;
- in = (in + 1) % N;
- mutex++;
- Sleep(sleepTime);
- } }
图2-2 生产者程序流程图
2.3 消费者问题
消费系统和生产系统有相似之处,如图2-3所示,首先系统进入初始化,完成这一步后需要立即判断库存的数量,因为当未生产商品时是不能进行商品销售的。如果判断目前库存数量为空,则立即停止销售,等待生产系统生产商品,并更新库存,进入下一个循环;反之,如果判断目前库存数量不为空,则开始进行销售,并进入下一个条件判断。
- void* consumer(void* b) {
- while (true) {
- while (full <= 0) {
- printf("库存为空!\n");
- }
- full--;
- while (mutex <= 0);
- mutex--;
- int nextc = buffer[out];
- buffer[out] = 0; //消费完将缓冲区设置为0
- out = (out + 1) % N;
- mutex++;
- empty++;
- consCount++;
- printf("\t\t\t\t陆小千 销售一个傻妞\n");
- printf("\t\t\t\t已销售产品数量:%d\n", consCount);
- Sleep(sleepTime);
- }
- }
图2-3 消费者程序流程图
2.4 进程问题
如图2-4的程序流程图,在编写程序时,首先需要定义一些信号量,用来控制对共享资源缓冲区的使用权限,前面已经介绍,我定义了mutex、empty、full、proCmutex 4个信号量。初始化变量之后,开始创建生产者进程和消费者进程;生产者生产的产品存放到缓冲区,发送信号量通知消费,此时消费者收到信号量开始销售产品。销售完一个产品,就释放掉一个缓冲区的空间位置。
图2-4 进程流程图
第3章 实验结果
3.1 运行结果
如图3-1、3-2所示,按照实验要求,在系统运行之前,打印出了我的个人信息,接着显示了生产的产品数量和当前的库存数量。按照实验要求,有4个工厂同时生产,有1个销售商进行销售,实验完成情况符合实验要求。
图3-1 运行初期界面
图3-2 运行中期界面
如图3-3、3-4所示,我设置的最大库存数量为100,当库存数量达到最大值时,打印:库存已满!并且停止生产,此时可以正常销售,当销售掉一个产品,此时库存数量小于100,这时又开始生产。并且实时打印了已销售的产品的数量。
图3-3 运行后期界面
图3-4 运行后期界面
3.2 结果分析
结合题目要求和实验的运行结果可以看出,实验结果达到了实验要求。在我的实验中程序中,创建了两个任务,并定义了信号量来控制两个任务之间的进程问题,加上生产-消费的逻辑关系,经过大量的测试修改代码,最终较好的完成了实验。
第4章 实验总结
在本次实验中,我查阅基于μC/OS-II操作系统的生产者与消费者问题的大量资料。认识到μC/OS-II作为一款开源的嵌入式实时操作系统,为并发编程提供了强大的支持。生产者与消费者问题作为一个经典的并发问题,其核心在于多个任务(生产者、消费者)如何安全、高效地共享有限资源(缓冲区)。
我首先定义了生产者和消费者两个任务,并分配了相应的优先级和栈空间。生产者任务负责模拟数据的生成并放入缓冲区,而消费者任务则负责从缓冲区中取出数据进行处理。在任务实现过程中,我也考虑了数据的一致性和同步性,确保生产者和消费者之间的协调运作。
为了实现生产者与消费者之间的同步和互斥,我采用了μC/OS-II的信号量机制。通过创建信号量并对其进行合理的操作(如P操作和V操作),我成功地实现了对缓冲区的访问控制,避免了数据竞争和混乱。
在完成基本功能后,我进行了大量的测试工作。通过模拟不同的生产速度和消费速度,我验证了系统的稳定性和可靠性。同时,我还对代码进行了优化,提高了系统的运行效率和响应速度。
本次实验让我深刻体会到了μC/OS-II操作系统在并发编程中的强大功能和灵活性。通过实际编程操作,我不仅掌握了生产者与消费者问题的解决方案,还深入理解了任务同步与通信机制的重要性。同时,我也认识到了在编写并发程序时需要注意的问题,如数据一致性和同步性等。此外,本次实验还锻炼了我的编程能力和解决问题的能力,提高了我的实践能力和综合素质。
在未来的学习和工作中,我将继续深入学习μC/OS-II操作系统和其他实时操作系统的知识,并将其应用于更复杂的并发编程问题中,以提升自己的编程水平和解决问题的能力。同时,非常感谢顾老师的本学期的辛勤付出以及对我的教导。