一. 实验目的
(1)加强对进程同步和互斥的理解,学会使用信号量解决资源共享问题。
(2)熟悉Linux 进程同步原语。
(3)掌握信号量wait/signal 原语的使用方法,理解信号量的定义、赋初值及wait/signal操作
二. 实验内容
(1)编写程序,使用Linux操作系统中的信号量机制模拟实现生产者-消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。
(2)以上实验只模拟了一个产品的放入与取出,请修改代码,以模拟实现多个产品的放入与取出。
三. 实验步骤
(1)编写程序,使用Linux操作系统中的信号量机制模拟实现生产者-消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。
#include <stdio.h> #include <pthread.h> #include <string.h> #include <stdlib.h> #include <semaphore.h> #define SIZE 256 sem_t empty, full, mutex; char *buffer; void *producer() { sem_wait(&empty); sem_wait(&mutex); printf("input something to buffer:\n"); buffer = (char *)malloc(SIZE); fgets(buffer, SIZE, stdin); sem_post(&mutex); sem_post(&full); } void *consumer() { sem_wait(&full); sem_wait(&mutex); printf("read product from buffer: %s\n", buffer); memset(buffer, 0, SIZE); sem_post(&mutex); sem_post(&empty); } int main() { pthread_t id_producer, id_consumer; int ret; sem_init(&empty, 0, 1); sem_init(&full, 0, 0); sem_init(&mutex, 0, 1); ret = pthread_create(&id_producer, NULL, producer, NULL); ret = pthread_create(&id_consumer, NULL, consumer, NULL); pthread_join(id_producer, NULL); pthread_join(id_consumer, NULL); sem_destroy(&empty); sem_destroy(&full); sem_destroy(&mutex); printf("The End ...\n"); return 0; }
该程序实现了生产者和消费者问题的解决方案,使用了三个信号量(empty、full和mutex)来控制生产和消费的进程访问缓冲区。
首先,程序定义了一个缓冲区(buffer),大小为256字节,用于生产者和消费者的数据交换。然后,使用了三个信号量来控制进程访问缓冲区的情况,其中,empty是缓冲区为空时的信号量,full是缓冲区为满时的信号量,mutex是用于保护缓冲区的互斥锁。
在producer函数中,生产者使用了P操作(sem_wait)操作empty和mutex信号量。如果empty信号量的值大于0,则表示缓冲区未满,可以向缓冲区中添加数据,否则就需要等待。同时,使用互斥锁mutex来保证缓冲区的同步访问。之后,生产者从标准输入中读取数据,将数据添加到缓冲区,并使用V操作(sem_post)操作mutex和full信号量,以此通知消费者缓冲区已经有数据可以读取。
在consumer函数中,消费者使用了P操作操作full和mutex信号量。如果full信号量的值大于0,则表示缓冲区有数据,可以读取,否则就需要等待。同样地,使用互斥锁mutex来保证缓冲区的同步访问。之后,消费者从缓冲区中读取数据,并将缓冲区清空。最后,使用V操作操作mutex和empty信号量,以此通知生产者缓冲区已经可写入新的数据。
在main函数中,创建了生产者和消费者进程,并等待它们完成。最后,使用sem_destroy函数来销毁信号量,并输出程序结束的信息。
总之,该程序使用了信号量来实现线程之间的同步,解决了生产者和消费者问题,保证了线程安全性和数据交换的可靠性。
(2)以上实验只模拟了一个产品的放入与取出,请修改代码,以模拟实现多个产品的放入与取出。
#include <stdio.h> #include <pthread.h> #include <string.h> #include <stdlib.h> #include <semaphore.h> #define SIZE 256 sem_t empty, full, mutex; char *buffer; void *producer() { while(1){ sem_wait(&empty); sem_wait(&mutex); printf("input something to buffer:\n"); buffer = (char *)malloc(SIZE); fgets(buffer, SIZE, stdin); sem_post(&mutex); sem_post(&full); } } void *consumer() { while(1){ sem_wait(&full); sem_wait(&mutex); printf("read product from buffer: %s\n", buffer); memset(buffer, 0, SIZE); sem_post(&mutex); sem_post(&empty); } } int main() { pthread_t id_producer, id_consumer; int ret; sem_init(&empty, 0, 1); sem_init(&full, 0, 0); sem_init(&mutex, 0, 1); ret = pthread_create(&id_producer, NULL, producer, NULL); ret = pthread_create(&id_consumer, NULL, consumer, NULL); pthread_join(id_producer, NULL); pthread_join(id_consumer, NULL); sem_destroy(&empty); sem_destroy(&full); sem_destroy(&mutex); printf("The End ...\n"); return 0; }
该程序是一个典型的生产者消费者问题的解决方案,使用了三个信号量(empty、full和mutex)来控制生产者和消费者访问缓冲区。不同之处在于,程序使用了while(1)循环,可以使生产者和消费者持续地向缓冲区中添加或读取数据,并避免在处理完一次数据后就退出的情况发生。
程序开始时,定义了一个缓冲区(buffer),大小为256字节,用于生产者和消费者的数据交换。接着,使用了三个信号量来控制进程访问缓冲区的情况,其中,empty是缓冲区为空时的信号量,full是缓冲区为满时的信号量,mutex是用于保护缓冲区的互斥锁。
在producer函数中,生产者使用了while(1)循环,表示生产者会一直运行下去。在循环中,生产者使用了P操作(sem_wait)操作empty和mutex信号量。如果empty信号量的值大于0,则表示缓冲区未满,可以向缓冲区中添加数据,否则就需要等待。同时,使用互斥锁mutex来保证缓冲区的同步访问。之后,生产者从标准输入中读取数据,将数据添加到缓冲区,并使用V操作(sem_post)操作mutex和full信号量,以此通知消费者缓冲区已经有数据可以读取。
在consumer函数中,消费者使用了while(1)循环,表示消费者会一直运行下去。在循环中,消费者使用了P操作操作full和mutex信号量。如果full信号量的值大于0,则表示缓冲区有数据,可以读取,否则就需要等待。同样地,使用互斥锁mutex来保证缓冲区的同步访问。之后,消费者从缓冲区中读取数据,并将缓冲区清空。最后,使用V操作操作mutex和empty信号量,以此通知生产者缓冲区已经可写入新的数据。
在main函数中,创建了生产者和消费者线程,并等待它们完成。最后,使用sem_destroy函数来销毁信号量,并输出程序结束的信息。
总之,该程序使用了信号量和互斥锁来实现线程之间的同步,解决了生产者和消费者问题,保证了线程安全性和数据交换的可靠性。使用while(1)循环可以使生产者和消费者持续地向缓冲区中添加或读取数据,并提高了程序的实用性。
四. 实验结果
(1)编写程序,使用Linux操作系统中的信号量机制模拟实现生产者-消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。
(2)以上实验只模拟了一个产品的放入与取出,请修改代码,以模拟实现多个产品的放入与取出。
五. 实验总结
本实验是通过对Linux操作系统中的信号量机制进行模拟实现,来深入理解多线程同步与互斥的概念和基本方法,同时也是对生产者-消费者模型的一个实际应用。
通过本次实验,我们深入了解了信号量的概念、使用方法以及相关的函数,并通过对生产者-消费者问题的模拟,掌握了相关的同步互斥机制。在实现过程中,我们使用了一个互斥信号量mutex来控制缓冲区和生产者、消费者之间的竞争,并使用了两个信号量full,empty来分别控制缓冲区是否已满或已空,从而实现了生产者和消费者之间的同步与互斥。
在实验中,我们还发现了一些问题和需要注意的地方。例如,在使用信号量时,需要保证每次操作都是原子操作,否则可能出现竞争条件,从而破坏了同步互斥机制。此外,还需要注意信号量的初始化以及销毁等问题,否则可能会出现资源泄漏等问题。
通过本次实验,我们不仅实现了生产者-消费者模型,并且深入理解了多线程同步与互斥的概念和方法,同时也锻炼了自己的编程能力和阅读和理解他人代码的能力。在今后的学习和工作中,我们将更好地应用信号量机制和多线程编程,并不断深化对操作系统和计算机原理的理解。