首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >饮食哲学家在C语言中的变异

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

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

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

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

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

main.c

代码语言:javascript
运行
复制
#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
运行
复制
#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
运行
复制
#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
运行
复制
#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 17: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

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档