DDD操作系统实验(六)

实验目的

  • 理解进程同步与进程互斥的概念。
  • 学会使用peterson算法、PV信号量方法解决进程同步与互斥问题。

实验内容

第一步:我们假设一种最简单producer-consumer的情况:
当前系统中有两个进程在并发执行,它们分别是producer与consumer。其中,producer与consumer共享变量counter,它们分别对counter进行了修改。附件simple_producer_consumer_peterson.c给出了这样的一种情形。

  • A. 运行该程序会出现什么后果?
  • B. 请使用peterson算法解决该问题。
  • C. 你的系统是如何调度peterson算法的?这个结果是否符合预期?

第二步:其实,我们可以使用更简单的系统调用来完成上述互斥问题。
只要定义一个互斥量mutex,然后使用系统的线程锁就可以完成上述事情。
可以参考下面的做法:

  • pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • pthread_mutex_lock(&mutex);
  • pthread_mutex_unlock(&mutex);

现在你可以试着将上面的peterson算法换成线程锁。

第三步:现在,我们来尝试更复杂的producer-consumer的情况
当前系统中有P_NUM+C_NUM个进程在并发执行,它们分别是P_NUM个producerC_NUM个consumer。其中,producer与consumer共享一个buffer,buffer的深度是BUF_SIZE。我们要求:一次只能有一个进程访问buffer,buffer满时不可以写,buffer空时不可以读。

现在,你可以思考下用信号量如何解决上述问题,然后参考我们的附件代码“complicated_producer_consumer.c”,观察参考代码是如何利用信号量解决问题。本部分需要你观察、运行所给的代码,掌握如何使用信号量解决进程同步问题。这个代码尽管能够实现所述功能,但也有点问题,欢迎同学们指出并完善它。

第四步:请将你的学号最后1位数字数模5,得到的结果对应接下来你需要解决的问题的序号,要根据PPT要求的输入输出来完成。如果对应的问题在PPT中没有要求,则需要自定义输入输出格式,保证整洁简单。可以在应做题目之外选择多做一题,有加分。

  1. 读者-写者问题,读者优先(PPT中有格式定义要求)
  2. 读者-写者问题,公平竞争(PPT中有格式定义要求)
  3. 读者-写者问题,写者优先(PPT中有格式定义要求)
  4. 哲学家进餐问题(需要用两种方法完成)
  5. 理发师问题

实验结果

第一步

  1. 原代码运行结果及分析
    在这里插入图片描述

  2. 你的运行结果及分析

int counter;
int turn=0;
int flag[2];
void *producer(void *param){
        flag[0] = 1;
        turn = 1;
        while(flag[1] && turn==1);
        int i;
        int a;
        for (i=0;i<10;i++){
                a=counter;
                sleep_rand_time();//or sleep(1);
                counter=a+1;
                printf("producer %d\n",counter);
        }
        printf("producer end\n");
        flag[0]=0;
        pthread_exit(0);
}
void *consumer(void *param){
        flag[1] = 1;
        turn=0;
        while(flag[0] && turn==0);
        int j;
        int b;
        for (j=0;j<10;j++){
                b=counter;
                sleep_rand_time(); //or sleep(1);
                counter=b-1;
                printf("consumer %d\n",counter);
        }
        printf("consumer end\n");
        flag[1]=0;
        pthread_exit(0);
}

在这里插入图片描述producer和consumer并发执行,用flag[]数组和turn标记,系统先调用consumer,并且在其结束之前一直是先让consumer执行,导致了producer一直在执行while循环无法进入临界区.

第二步:

  1. 使用Peterson算法如何解决问题,运行结果及分析
    在这里插入图片描述
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *producer(void *param){
        pthread_mutex_lock(&mutex);
        int i;
        int a=0;
        for (i=0;i<10;i++){
                a=counter;
                sleep_rand_time();//or sleep(1);
                counter=a+1;
                printf("producer %d\n",counter);
        }
        printf("producer end\n");
        pthread_mutex_unlock(&mutex);
        pthread_exit(0);
}
void *consumer(void *param){
        pthread_mutex_lock(&mutex);
        int j;
        int b=10;
        for (j=0;j<10;j++){
                b=counter;
                sleep_rand_time(); //or sleep(1);
                counter=b-1;
                printf("consumer %d\n",counter);
        }
        printf("consumer end\n");
        pthread_mutex_unlock(&mutex);
        pthread_exit(0);
}

用线程锁替换turn和flag,pthread_mutex_t创建一个互斥锁,再用pthread_mutex_lock(&mutex);和pthread_mutex_unlock(&mutex);分别在producer和consumer中的临界区前后添加

  1. 使用信号量如何解决问题,运行结果及分析
#include <semaphore.h>
sem_t sem;
void *producer(void *param){
        sem_wait(&sem);
        int i;
        int a=0;
        for (i=0;i<10;i++){
                a=counter;
                sleep_rand_time();//or sleep(1);
                counter=a+1;
                printf("producer %d\n",counter);
        }
        printf("producer end\n");
        sem_post(&sem);
        pthread_exit(0);
}
void *consumer(void *param){
        sem_wait(&sem);
        int j;
        int b=10;
        for (j=0;j<10;j++){
                b=counter;
                sleep_rand_time(); //or sleep(1);
                counter=b-1;
                printf("consumer %d\n",counter);
        }
        printf("consumer end\n");
        sem_post(&sem);
        pthread_exit(0);
}
int main(int argc, char *argv[]){
        sem_init(&sem,0,1);

定义信号量sem,主函数初始化信号量sem_init,分别在producer和consumer中的临界区前后添加sem_wait()和sem_post()替代线程锁。

第三步:

  1. 运行所给代码结果及分析
    Main函数创建5个producer线程和5个comsumer线程,在这两个线程中使用pv信号量确保buf_size保持正常,使用线程锁保证有且仅有一个进程能访问buffer,程序需要手动退出。
    在这里插入图片描述

第四步:

  1. 请描述你是如何解决该问题的(解决策略详述)?
    读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变量read_count记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当read_count=0时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。每一个读者开始读文件时,必须修改read_count变量。因此需要一个互斥对象mutex来实现对全局变量read_count修改时的互斥。
    为了实现写-写互斥,需要增加一个临界区对象write。当写者发出写请求时,必须申请临界区对象的所有权。通过这种方法,也可以实现读-写互斥,当read_count=1时(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。
  2. 得到了怎样的结果?这个结果与预期相符吗?为什么?
    测试数据:
    1 R 1 3
    2 W 2 7
    3 R 3 2
    4 W 5 5
    5 W 5 13

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

当读者拥有临界区的所有权时,写者阻塞在临界区对象write上。当写者拥有临界区的所有权时,第一个读者判断完“read_count==1”后阻塞在write上,其余的读者由于等待对read_count的判断,阻塞在mutex上。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
无界零售系统搭建中的DDD和微服务是两个关键的实战方法。 领域驱动设计(DDD)是一种软件开发方法论,强调在设计和实现过程中将业务逻辑置于核心位置。在无界零售系统中,DDD可以帮助我们更好地理解业务需求,通过对业务领域的建模和解析,提取出核心的业务概念和逻辑,并将其转化为可操作的代码。 在无界零售系统搭建的过程中,微服务架构可以帮助我们将整个系统拆分为多个小而独立的服务单元,每个服务单元都可以独立进行开发、测试和部署。微服务可以提供更高的灵活性和可扩展性,同时也提供了更好的容错和可恢复性。在无界零售系统中,我们可以将不同的业务模块和功能拆分成独立的微服务,例如订单管理、用户管理、库存管理等。 通过将DDD和微服务相结合,我们可以建立一个高度灵活、高度可扩展的无界零售系统。首先,DDD可以帮助我们清晰地定义和理解业务需求,并将其转化为可操作的代码。其次,微服务架构可以将整个系统分解为多个独立的服务单元,充分利用分布式环境下的优势。这些服务单元可以独立进行开发、测试和部署,同时也更容易进行扩展和维护。 在实践中,我们可以先进行业务领域的分析和建模,分析系统中的核心业务流程和概念,并将其转化为领域对象。然后,我们可以将这些领域对象归类到不同的微服务中,每个微服务负责处理相关的业务功能。最后,我们可以利用现有的微服务框架和工具来实现这些微服务,并通过适当的API和消息机制来实现微服务之间的交互。 综上所述,通过应用DDD和微服务,我们可以更好地构建无界零售系统,提高系统的灵活性、可扩展性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值