Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >饮食哲学家在C语言中的变异

饮食哲学家在C语言中的变异
EN

Code Review用户
提问于 2016-12-01 13:24:32
回答 1查看 615关注 0票数 5

这是餐饮哲学家问题的一个变体。任务是协调几个学生在健身房内。所有的学生都试图从一个共同的重量架上获得他们想要的训练重量。在运行时,用户可以发出命令:

  • 阻止学生(b +学生身份)
  • 解除对学生的阻碍(u +学生id)
  • 继续(p +学生id) (结束学生的锻炼/休息循环)
  • 结束程序(q或Q)

我是C语言的初学者,希望了解如何改进我的代码。

main.c

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <pthread.h>
#include "main.h"
#include "gym_monitor.h"
/*
*
*   Main module of the Thread-Coordination Exercise. This modul contains
*   the main function which creates the threads. After creation all threads
*   enter the gym_routine function.
*
*/
#define REST_LOOP     1000000000
#define WORKOUT_LOOP  500000000

#define WEIGHTS_ANNA        6
#define WEIGHTS_BERND       8
#define WEIGHTS_CLARA_DIRK 12
#define WEIGHTS_EMMA       14

#define MAX_INPUT_SIZE 3

#define WEIGHT_RACK_DEF {4,4,5}

static pthread_barrier_t gym_routine_barrier;

static void workout(Student* student) {
  for( int i = 0; i < WORKOUT_LOOP; i++ ) {
    if(student->status == BLOCKED) {
      rest_student(student);
    }else if(student->status == PROCEED) {
      student->status = NORMAL;
      break;
    }
  }
}

static void rest(Student* student) {
  for( int i = 0; i < REST_LOOP; i++ ) {
    if(student->status == BLOCKED) {
      rest_student(student);
    }else if(student->status == PROCEED) {
      student->status = NORMAL;
      break;
    }
  }
}

static void* gym_routine(void* stud) {
  pthread_barrier_wait(&gym_routine_barrier);
  Student* student = (Student*) stud;
  while(student->status != QUIT) {
    get_weights(student);
    workout(student);
    put_weights(student);
    rest(student);
  }
  return NULL;
}

int main(void) {

  char available_weights[] = WEIGHT_RACK_DEF;

  int students_weights[] = {WEIGHTS_ANNA,WEIGHTS_BERND,WEIGHTS_CLARA_DIRK,
                            WEIGHTS_CLARA_DIRK,WEIGHTS_EMMA};

  Student students[NR_STUDENTS];
  monitor_vars* monitor = init_monitor();

  pthread_barrier_init(&gym_routine_barrier, NULL, NR_STUDENTS);

  int res;
  for( int i = 0; i < NR_STUDENTS; i++ ) {
    students[i].thread_id = i;
    students[i].weight_plan = students_weights[i];
    students[i].status = NORMAL;

    for(int j = 0; j < NR_WEIGHTS; j++) {
      students[i].current_weight[j] = 0;
    }
    students[i].mon = monitor;
    students[i].sem_student = init_sem_student();
    students[i].other_students = students;
    students[i].weight_rack = available_weights;


    res = pthread_create(&students[i].thread, NULL, gym_routine,
                         (void*) &students[i]);
    if(res != 0) {
      perror("Thread creation failed");
      exit(EXIT_FAILURE);
    }
  }

  /*Handling user input*/
  char input[MAX_INPUT_SIZE] = {0};
  while(strncasecmp(fgets(input, MAX_INPUT_SIZE, stdin),"q", 1))  {

    /* trying to get rid of newline from input
      this is the only 'solution' that works so far*/
    if(input[0] == '\n' || input[0] == '\0') {
      continue;
    }

    fflush(stdout);
    if((input[0] - '0') >= 0 && (input[0] - '0') < NR_STUDENTS
      && strchr("bpu", input[1]) && strlen(input) == 2 ) {
        int student_id = input[0] - '0';

        students[student_id].status = input[1];
        if(students[student_id].status == UNBLOCK) {
          wake_student(&(students[student_id]));
          students[student_id].status = NORMAL;      
        }
      }else {
        printf("Not a valid instruction\n");
        fflush(stdout);
      }
    }

  /*updating student status*/
  for(int i = 0; i < NR_STUDENTS; i++) {
    wake_student(&students[i]);     //students can only quit if they are not asleep
    students[i].status = QUIT;
  }

  for(int i = 0; i < NR_STUDENTS; i++) {
      pthread_join(students[i].thread,NULL);
      destroy_sem_student(&students[i]);
      free(students[i].sem_student);
  }
  destroy_monitor(monitor);
  exit(EXIT_SUCCESS);
}

main.h

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ifndef MAIN_H
#define MAIN_H
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <strings.h>
#include "gym_monitor.h"

enum weight_names{
  KG_2,
  KG_3,
  KG_5
};

#define BLOCKED 'b'
#define PROCEED 'p'
#define NORMAL  'n'
#define UNBLOCK 'u'
#define QUIT    'q'

#define NR_WEIGHTS  3
#define NR_STUDENTS 5

typedef struct Student Student;

struct Student  {
  pthread_t thread;
  int thread_id;
  int weight_plan;
  char status;
  char training_state;
  char current_weight[NR_WEIGHTS];
  monitor_vars* mon;
  sem_t* sem_student;
  Student* other_students;
  char* weight_rack;
};

#endif

gym_Monitor.c

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "gym_monitor.h"
#include "main.h"

/*
*   Monitor module - Encapsulates all objects and functions that manage
*   thread-coordination.
*
*/

#define MAX_2KG_3KG 4
#define MAX_5KG 5
#define RED   "\x1B[31m"
#define RESET "\x1B[0m"

const int weight_arr[] = {
  [KG_2] = 2,
  [KG_3] = 3,
  [KG_5] = 5
};


static int calculate_weight(Student* student, int weight) {
  if(weight == 0) {
    return 1;
  }

  if(weight >= weight_arr[KG_2] && student->weight_rack[KG_2] > 0) {
    student->weight_rack[KG_2] -= 1;
    student->current_weight[KG_2] += 1;

    if(!calculate_weight(student, weight - weight_arr[KG_2])) {
      student->weight_rack[KG_2] += 1;
      student->current_weight[KG_2] -= 1;
    }else {
      return 1;
    }

    if(weight >= weight_arr[KG_3] && student->weight_rack[KG_3] > 0) {
      student->weight_rack[KG_3] -= 1;
      student->current_weight[KG_3] += 1;

      if(!calculate_weight(student, weight - weight_arr[KG_3])) {
        student->weight_rack[KG_3] += 1;
        student->current_weight[KG_3] -= 1;
      }else {
        return 1;
      }
    }

    if(weight >= weight_arr[KG_5] && student->weight_rack[KG_5] > 0) {
      student->weight_rack[KG_5] -= 1;
      student->current_weight[KG_5] += 1;

      if(!calculate_weight(student, weight - weight_arr[KG_5])) {
        student->weight_rack[KG_5] += 1;
        student->current_weight[KG_5] -= 1;
      }else {
        return 1;
      }
    }
  }

  return 0;
}

static void display__status(Student* student) {
  int consistency_check[] = {0,0,0};

  for(int i = 0; i < NR_STUDENTS; i++) {
    printf("%d(%d)%c:%c:[%d, %d, %d]  ",student->other_students[i].thread_id,
                                        student->other_students[i].weight_plan,
                                        student->other_students[i].status,
                                        student->other_students[i].training_state,
                                        student->other_students[i].current_weight[KG_2],
                                        student->other_students[i].current_weight[KG_3],
                                        student->other_students[i].current_weight[KG_5]);

    consistency_check[KG_2] += student->other_students[i].current_weight[KG_2];
    consistency_check[KG_3] += student->other_students[i].current_weight[KG_3];
    consistency_check[KG_5] += student->other_students[i].current_weight[KG_5];
  }
  if(  consistency_check[KG_2] > MAX_2KG_3KG
    || consistency_check[KG_3] > MAX_2KG_3KG
    || consistency_check[KG_5] > MAX_5KG ) {
      printf(RED "Inconsistent State\n" );
      printf("[%d, %d, %d]\n" RESET,consistency_check[KG_2],
                              consistency_check[KG_3],
                              consistency_check[KG_5]);
  }else {
      printf("Supply: [%d, %d, %d]\n", student->weight_rack[KG_2],
                                       student->weight_rack[KG_3],
                                       student->weight_rack[KG_5]);
  }
  fflush(stdout);
}


void get_weights(Student* student) {
  pthread_mutex_lock(&student->mon->lock);
  student->training_state = GET_WEIGHTS;
  while(!calculate_weight(student, student->weight_plan)) {
    student->training_state = BLOCKED;
    display__status(student);
    pthread_cond_wait(&student->mon->insufficient_weight, &student->mon->lock);
    if(student->status != QUIT) {
      student->status = NORMAL;
    }
  }

  display__status(student);
  student->training_state = WORKOUT;
  pthread_mutex_unlock(&student->mon->lock);
}

void put_weights(Student* student) {
  pthread_mutex_lock(&student->mon->lock);
  student->training_state = PUT_WEIGHTS;

  student->weight_rack[KG_2] += student->current_weight[KG_2];
  student->weight_rack[KG_3] += student->current_weight[KG_3];
  student->weight_rack[KG_5] += student->current_weight[KG_5];

  for(int i = 0; i < NR_WEIGHTS; i++) {
    student->current_weight[i] = 0;
  }

  display__status(student);
  pthread_cond_signal(&student->mon->insufficient_weight);
  student->training_state = REST;
  pthread_mutex_unlock(&student->mon->lock);
}

void rest_student(Student* student) {
  sem_wait(student->sem_student);
}

void wake_student(Student* student) {
  sem_post(student->sem_student);
}

sem_t* init_sem_student() {
  int res = 0;
  sem_t* sem_student = malloc(sizeof(sem_t));
  if(sem_student == NULL) {
    perror("malloc failed, exiting...");
    exit(EXIT_FAILURE);
  }
  res = sem_init(sem_student,0,1);
  if(res != 0) {
    perror("Semaphore creation failed");
    exit(EXIT_FAILURE);
  }
  return sem_student;
}

void destroy_sem_student(Student* student) {
  int res = 0;

  res = sem_destroy(student->sem_student);
  if(res != 0) {
    perror("Destroying semaphore failed");
    exit(EXIT_FAILURE);
  }
}

monitor_vars* init_monitor() {
  int res = 0;
  monitor_vars* monitor_vars_ptr = malloc(sizeof(monitor_vars));
  if(monitor_vars_ptr == NULL) {
    perror("malloc failed, exiting...");
    exit(EXIT_FAILURE);
  }

  res = pthread_mutex_init(&monitor_vars_ptr->lock, NULL);
  if(res != 0) {
    perror("Mutex creation failed");
    exit(EXIT_FAILURE);
  }

  res = pthread_cond_init(&monitor_vars_ptr->insufficient_weight, NULL);
  if(res != 0) {
    perror("Condition Variable creation failed");
    exit(EXIT_FAILURE);
  }
  return monitor_vars_ptr;
}

void destroy_monitor(monitor_vars* monitor_vars_ptr) {
  int res = 0;
  res = pthread_mutex_destroy(&monitor_vars_ptr->lock);
  if(res != 0) {
    perror("Destroying mutex failed");
    exit(EXIT_FAILURE);
  }
  res = pthread_cond_destroy(&monitor_vars_ptr->insufficient_weight);
  if(res != 0) {
    perror("Destroying condition variable failed");
    exit(EXIT_FAILURE);
  }
  free(monitor_vars_ptr);
}

gym_monitor.h

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ifndef MONITOR_H
#define MONITOR_H

#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>

#define REST        'R'
#define WORKOUT     'W'
#define GET_WEIGHTS 'G'
#define PUT_WEIGHTS 'P'

struct Student;

typedef struct {
  pthread_mutex_t lock;
  pthread_cond_t insufficient_weight;
}monitor_vars;

/*
*   Manages the weight distribution among the students.
*   Students enter the function, lock the mutex and try to obtain
*   their corresponding weight. If the weight is not obtainable
*   the student is waiting on a condition variable. Otherwise the
*   student picks the weight and unlocks the mutex.
*
*   parameter - the student
*   return    - none
*/
void get_weights(struct Student* stud);

/*
*   Coordinates the transfer of weights from students back to the
*   weight rack inside a monitor.
*
*   parameter - the student
*   return    - none
*/
void put_weights(struct Student* stud);

/*
*   Student waits on a semaphore
*
*   parameter - the student
*   return    - none
*/
void rest_student(struct Student* stud);

/*
*   Student waiting on a semaphore is unblocked
*
*   parameter - the student
*   return    - none
*/
void wake_student(struct Student* stud);

/*
*   Creates, initializes and returns a struct of monitor_vars.
*   The struct contains a mutex and a condition variable.
*   Exits the program if either memory allocation or initializing fails.
*
*   parameter - none
*   return    - the mutex and condition variable inside a monitor_vars struct
*/
monitor_vars* init_monitor();

/*
*   Destroys the supplied monitor struct.
*   Exits the program if destroying the monitor fails.
*
*   parameter - the monitor struct to be destroyed
*   return    - none
*/
void destroy_monitor(monitor_vars* mon);

/*
*   Creates, initializes and returns a semaphore.
*   Exits the program if either memory allocation or initializing fails.
*
*   parameter - none
*   return    - the initialized semaphore
*/
sem_t* init_sem_student();

/*
*   Destroys the semaphore of the supplied student.
*   Exits the program if destroying the semaphore fails.
*
*   parameter - the student
*   return    - none
*/
void destroy_sem_student(struct Student* student);

#endif
EN

回答 1

Code Review用户

发布于 2016-12-02 09:44:32

  1. 避免对用户输入缓冲区的吝啬。更好地平衡“适当大小”缓冲区(3)的想法,用户从时间到时间都会输入过多的文本。与其在stdin中留下额外的文本,不如阅读这一行。通常,建议2倍于预期的最大需求,或者创建代码,这些代码将消耗用户输入行中过多的文本。// #定义MAX_INPUT_SIZE 3#定义MAX_INPUT_SIZE (3*2)char输入最大值_输入_大小= {0};while(strncasecmp(fget( MAX_INPUT_SIZE,stdin),"q",1)) {
  2. 减少潜在尾随'\n'的一个简单方法是:输入strcspn(输入,“\n”)= '\0';
  3. fflush(stdout);fgets()后的价值尚不清楚。如果有的话,在fgets()之前进行编码可能会增加价值。
  4. 考虑编写一个变量,以帮助详细说明NULL的内容。// pthread_barrier_init(&gym_routine_barrier,NULL,NR_STUDENTS);const pthread_barrierattr_t *attr = NULL;pthread_barrier_init(&gym_routine_barrier,attr,NR_STUDENTS);
  5. 健壮的代码将检查pthread_barrier_init()的结果。
  6. 当对象是常量时,使用const有助于将其传递给审阅者,并有助于一些编译器优化。// int students_weights[] = {WEIGHTS_ANNA,WEIGHTS_BERND,.students_weights[] = {WEIGHTS_ANNA,WEIGHTS_BERND,.
  7. 对于数组索引和大小调整,size_t是Goldilocks类型,既不太窄也不太宽,只是适合所有索引。// for( int I= 0;i< NR_STUDENTS;i++ ){ for( size_t i= 0;i< NR_STUDENTS;i++ ){我.thread_id= i;
  8. 名称空间组织:在gym_monitor.h内部,出现像RESTStudentmonitor_vars这样的ID。在使用这些标识符的*.c文件中,不清楚它们起源于何处。像REST这样的定义肯定会与其他代码发生冲突。也许使用gym_RESTgym_Student或其他一些方案会有所帮助。
  9. 灵活的代码:consistency_check[]的大小随enum weight_names的不同而变化。因此,使用固定的int consistency_check[] = {0,0,0}是一个问题,如果重量名称的数目改变。建议: enum weight_names{ KG_2,KG_3,KG_5,weight_names_N };int consistency_check重量_名字_N = {0};

GTG

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/148688

复制
相关文章
RDKit:计算不同小分子构象之间的RMSD
python isoRMSD.py mol1.pdb mol2.pdb rmsd.txt
DrugAI
2021/01/28
1.6K0
小程序flex布局
目录的规范,所有组件要放在components目录下,所有图片要放在images目录下,模型文件时用于编写各类业务的模型,需要放在models文件下。
达达前端
2019/07/03
7220
小程序flex布局
Flex简单小程序
主mxml: <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009
三产
2021/01/13
5210
「小程序JAVA实战」小程序的flex布局(22)
整个是一个大盒子,大盒子里面有很多的小块a,b,c,d,e,f都是他的成员,针对其中的成员可以增加对应的样式,可以看出来a,b,d是比较大的,c是最小的,我们可以通过样式控制它们的大小,我们也可以通过order的方式控制他们的位置顺序,一般正常的咱们的页面都有顺序的,可以通过布局的order属性,把顺序给展示出来。
IT架构圈
2018/12/25
8150
【微信小程序】flex布局
哈喽大家好,本期是微信小程序的第四期,本期主要内容:flex布局。 ps:本期有引用上期内容噢~
颜颜yan_
2022/12/01
4580
【微信小程序】flex布局
微信小程序flex布局
https://www.cnblogs.com/sun8134/p/6395947.html
似水的流年
2020/09/10
8740
flex-grow计算公式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style type="text/css"> *{ margin: 0; padding: 0;
贵哥的编程之路
2020/10/28
8770
小程序 flex_fly app
在小程序中使用请求,只能使用原生的wx.request,如果想要向axios一样使用三方包,只能使用flyio,不然会报错,同时flyio是属于多种兼容的可以放心使用到多端。
全栈程序员站长
2022/10/04
3160
flex-shrink计算公式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style type="text/css"> *{ margin: 0; padding: 0; }
贵哥的编程之路
2020/10/28
8320
Flex之计算器实现
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" lay
牛老师讲GIS
2018/10/23
6180
小程序之首页搭建——Flex布局
布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性
用户10196776
2023/10/17
4720
小程序之首页搭建——Flex布局
实时数据计算框架演进介绍
数仓建设是公司数据发展到一定规模后必然会提供的一种基础服务,其中数仓建设也是“数据智能”中必不可少的一环。本文将从数据仓库的简介、经历了怎样的发展、如何建设、架构演变、应用案例以及实时数仓与离线数仓的对比六个方面全面分享关于数仓的详细内容。
数字悠客
2020/08/04
2K0
小程序-实现小程序与小程序之间的跳转
使用标签的方式跳转,非常简单,只需要在wxml中使用target,open-type,app-id,path,指定相应的参数就可以实现跳转了的
itclanCoder
2020/11/06
8.2K0
mysql计算日期之间相差的天数
有两种方式可以获得mysql两个日期之间的差值,一种是使用TO_DAYS函数,另一种是datediff函数
用户8983410
2021/11/01
4.3K0
写给 Android 开发的小程序布局指南,Flex 布局!
最近在做小程序,验证一些方向,开发效率确实很快,就是各种微信的审核有点费劲,但是总归是有办法解决的。
Android技术干货分享
2019/07/04
1K0
微信小程序-view元素Flex布局
对于网页布局,推荐 Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。可以参考完全教材,我推荐一个阮老师的,下面是链接
叉叉敌
2019/08/23
9190
小程序之间互相跳转
小程序之间互相跳转,使用 *wx.navigateToMiniProgram *来实现。 不同主体的小程序可以相互跳转,不需要关联小程序(重点)。 官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/navigate/wx.navigateToMiniProgram.html
leader755
2022/03/09
6K0
小程序之间互相跳转
大数据和云计算之间的区别
云计算爱好者
2018/01/03
2.7K0
JVM与计算机之间的关系
计算机内存硬件架构 [image-20201224230943962] CPU,一台现代计算机拥有两个或多个CPU,其中一些CPU还有多核,从这一点可以看出,在一个有两个或多个CPU的现代计算机上,同时运行多个线程是非常有可能的,而且每个CPU在某一个时刻,运行一个线程是肯定没有问题的,这意味着,如果Java程序是多线程的,在Java程序中,每个CPU上一个线程是可能同时并发执行的。 CPU Refisters(寄存器),每个CPU都包含一系列的寄存器,它们是CPU内存的基础,CPU在寄存器中执行操作的速度
开源日记
2021/01/05
8910
Applet小应用程序之间的通讯
1、 首先解压:如何运行applet.zip文件,解压后如图
张泽旭
2018/12/10
8370
Applet小应用程序之间的通讯

相似问题

如何计算两次之间浮动的小时数?

214

如何使用jquery计算两次之间的小时数?

40

在sql server中计算两次之间的小时数

24

计算轮班之间的小时数

00

计算范围SQL之间的小时数

130
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文