【操作系统】多线程同步与互斥

文章目录

  • [一. 实验目的](#一. 实验目的)
  • [二. 实验内容](#二. 实验内容)
  • [三. 实验步骤](#三. 实验步骤)
  • [四. 实验结果](#四. 实验结果)
  • [五. 实验总结](#五. 实验总结)

一. 实验目的

(1)加强对进程同步和互斥的理解,学会使用信号量解决资源共享问题。

(2)熟悉Linux 进程同步原语。

(3)掌握信号量wait/signal 原语的使用方法,理解信号量的定义、赋初值及wait/signal操作

二. 实验内容

(1)编写程序,使用Linux操作系统中的信号量机制模拟实现生产者-消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。

(2)以上实验只模拟了一个产品的放入与取出,请修改代码,以模拟实现多个产品的放入与取出。

三. 实验步骤

(1)编写程序,使用Linux操作系统中的信号量机制模拟实现生产者-消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。

c 复制代码
#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)以上实验只模拟了一个产品的放入与取出,请修改代码,以模拟实现多个产品的放入与取出。

c 复制代码
#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来分别控制缓冲区是否已满或已空,从而实现了生产者和消费者之间的同步与互斥。

在实验中,我们还发现了一些问题和需要注意的地方。例如,在使用信号量时,需要保证每次操作都是原子操作,否则可能出现竞争条件,从而破坏了同步互斥机制。此外,还需要注意信号量的初始化以及销毁等问题,否则可能会出现资源泄漏等问题。

通过本次实验,我们不仅实现了生产者-消费者模型,并且深入理解了多线程同步与互斥的概念和方法,同时也锻炼了自己的编程能力和阅读和理解他人代码的能力。在今后的学习和工作中,我们将更好地应用信号量机制和多线程编程,并不断深化对操作系统和计算机原理的理解。

相关推荐
秋风起,再归来~6 分钟前
【Linux庖丁解牛】—Linux基本指令(中)!
linux·指令
Eternal-Student17 分钟前
预处理、编译、汇编、链接
linux·汇编·windows
学无止境\n1 小时前
[C语言]指针和数组
c语言·数据结构·算法
sp_wxf1 小时前
Stream流
linux·服务器·windows
LYK_HAHA1 小时前
centos常用知识和命令
linux·运维·centos
可涵不会debug2 小时前
【Linux】信号知识三把斧——信号的产生、保存和处理
linux·运维·信号
jyan_敬言2 小时前
【Linux】Linux命令与操作详解(一)文件管理(文件命令)、用户与用户组管理(创建、删除用户/组)
linux·运维·服务器·c语言·开发语言·汇编·c++
bcdaren3 小时前
《Windows PE》4.2 绑定导入表
c语言·汇编·windows·pe
unix2linux3 小时前
Parade Series - SHA256
linux·python·mysql·shell
jmlinux3 小时前
环形缓冲区(Ring Buffer)在STM32 HAL库中的应用:防止按键丢失
c语言·stm32·单片机·嵌入式硬件