小冯Sir 2024-06-02 20:37 采纳率: 0%
浏览 7
已结题

C语言生产者和消费者模型的一些问题(相关搜索:c语言)

问题

第一个问题就是消费者线程并不能优雅的退出,想要的是当生产者线程退出后,消费者线程也应该退出。我这里使用了标志位发现依旧不能优雅的退出。
第二个问题就是当生产者获取用户输入后,消费者线程并不能及时消费。这个不知道怎么搞。

img

编译环境

系统:Windows11
工具链:mingw
IDE:Clion

代码片段

main.c

#include "stdio.h"
#include "pthread.h"
#include "buffer.h"
#include "student.h"

#define INPUT_SIZE 64
int input_count = 0;
pthread_mutex_t mutex;
pthread_cond_t input_count_cond;

void *producerThread(void *arg) {
  char input[INPUT_SIZE];
  queue *cb = (queue *)arg;
  while (1) {
    pthread_mutex_lock(&mutex);
    printf("请输入数据:\n");
    fflush(stdout);
    if (fgets(input, INPUT_SIZE, stdin) == NULL) {
      break;
    }
    pthread_mutex_unlock(&mutex);
    if (strncmp(input, "exit", 4) == 0) {
      break;
    }
    size_t len = strlen(input);
    if (len > 0 && input[len - 1] == '\n') {
      input[len - 1] = '\0';
    }
    static char last_char = '\0';
    int i;
    for (i = 0; input[i] != '\0'; ++i) {
      char current_char = input[i];
      if (current_char == last_char) {
        continue;
      }
      Enqueue(cb, current_char);
      pthread_mutex_lock(&mutex);
      printf("在位置 %d 写入了字符 '%c'\n", (cb->tail % BUFFER_SIZE), current_char);
      pthread_mutex_unlock(&mutex);
      last_char = current_char;
      cb->producing = 0;
      pthread_cond_signal(&cb->not_empty);
    }
    pthread_mutex_lock(&mutex);
    input_count = i;
    pthread_cond_signal(&input_count_cond);
    pthread_mutex_unlock(&mutex);
  }
  pthread_mutex_lock(&mutex);
  cb->running = 0;
  pthread_cond_signal(&input_count_cond);
  pthread_mutex_unlock(&mutex);
  return NULL;
}

void *ConsumerThread(void *arg) {
  queue *cb = (queue *)arg;
  char item;
  char input[INPUT_SIZE];
  int count = 0;
  int temp_count = 0;
  char class[20],lastname[NAME_LENGTH],firstname[NAME_LENGTH],id[12];
  while (1) {

    if (Dequeue(cb, &item)) {
      pthread_mutex_lock(&mutex);
      printf("在%d位置读取了字符'%c'\n", cb->head, item);
      while (temp_count == 0){
        pthread_cond_wait(&input_count_cond,&mutex);
        temp_count = input_count;
      }
      pthread_mutex_unlock(&mutex);

      input[count++] = item;
      input[count] = '\0';
      if(count == temp_count){
        pthread_mutex_lock(&mutex);
        if(!splitClassNameId(input,class,lastname,firstname,id)){
          printf("数据解析错误!请检测输入格式!\n");
          count = temp_count = 0;
          memset(input,0,INPUT_SIZE);
          pthread_mutex_unlock(&mutex);
          continue;
        }
        count = temp_count = 0;
        memset(input,0,INPUT_SIZE);
        writeInfoToStu(&stu.stu[stu.count++],class,lastname,firstname,id);
        sortStudents(&stu);
        writeFirstNameToFile(stu.stu[stu.count-1]);
        pthread_mutex_unlock(&mutex);
      }
    } else {
      pthread_mutex_lock(&cb->mutex);
      while (!cb->producing && cb->count == 0) {
        pthread_cond_wait(&cb->not_empty, &cb->mutex);
      }
      pthread_mutex_unlock(&cb->mutex);

      if(cb->running && cb->count == 0){
        break;
      }
    }
  }
  return NULL;
}

int main() {

  queue *buffer = createQueue();
  InitStu();
  pthread_mutex_init(&mutex,NULL);
  pthread_cond_init(&input_count_cond,NULL);

  pthread_t producer_thread, consumer_thread;
  if (pthread_create(&producer_thread, NULL, producerThread, buffer) != 0) {
    perror("pthread_create failed");
    return 1;
  }
  if (pthread_create(&consumer_thread, NULL, ConsumerThread, buffer) != 0) {
    perror("pthread_create failed");
    return 1;
  }

  pthread_join(producer_thread, NULL);
  pthread_join(consumer_thread, NULL);

  pthread_mutex_destroy(&buffer->mutex);
  pthread_cond_destroy(&buffer->not_empty);
  pthread_cond_destroy(&buffer->not_full);
  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&input_count_cond);

  return 0;
}

buffer.c

#include "buffer.h"

queue *createQueue() {
  queue *q = (queue *)malloc(sizeof(queue));
  q->head = 0;
  q->tail = 0;
  q->count = 0;
  memset(q->buffer, 0, BUFFER_SIZE);
  pthread_mutex_init(&q->mutex, NULL);
  pthread_cond_init(&q->not_full, NULL);
  pthread_cond_init(&q->not_empty, NULL);
  q->running = 1;
  q->producing = 1;
  return q;
}
void Enqueue(queue *q, char str) {
  pthread_mutex_lock(&q->mutex);
  while (q->count == BUFFER_SIZE) {
    pthread_cond_wait(&q->not_full, &q->mutex);
  }
  q->buffer[q->tail] = str;
  q->tail = (q->tail + 1) % BUFFER_SIZE;
  q->count++;
  pthread_cond_signal(&q->not_empty);
  pthread_mutex_unlock(&q->mutex);
}

int Dequeue(queue *q, char *str) {
  pthread_mutex_lock(&q->mutex);
  while (q->count == 0 && q->producing) {
    pthread_cond_wait(&q->not_empty, &q->mutex);
  }

  if (q->count > 0) {
    *str = q->buffer[q->head];
    q->head = (q->head + 1) % BUFFER_SIZE;
    q->count--;
    pthread_cond_signal(&q->not_full);
    pthread_mutex_unlock(&q->mutex);
    return 1;
  } else {
    pthread_mutex_unlock(&q->mutex);
    return 0;
  }
}

buffer.h

#include "stdio.h"
#include "stdbool.h"
#include "string.h"
#include "pthread.h"
#include "stdlib.h"

#define BUFFER_SIZE 64

typedef struct QUEUE{
    char buffer[BUFFER_SIZE];
    int head;
    int tail;
    int count;
    pthread_mutex_t  mutex;
    pthread_cond_t  not_full;
    pthread_cond_t  not_empty;
    int running;
    int producing;

}queue;

queue *createQueue();
void Enqueue(queue *q,char str);
int Dequeue(queue *q,char *str);


  • 写回答

4条回答 默认 最新

  • 关注

    晚上好🌙🌙🌙
    本答案参考ChatGPT-3.5

    第一个问题:消费者线程不能优雅退出的问题

    针对消费者线程不能优雅退出的问题,你可以尝试以下解决方案:

    1. 在生产者线程退出后,向消费者线程发送退出信号:在生产者线程退出时,通过修改一个全局变量或使用特定的信号量来通知消费者线程退出。消费者线程在每次循环迭代时检查是否收到退出信号,如果收到则退出循环退出线程。

    2. 使用条件变量控制消费者线程退出:在生产者线程退出时,通过条件变量或互斥锁来通知消费者线程退出。消费者线程在每次循环迭代时,检查条件变量的状态,如果满足退出条件则退出循环退出线程。

    3. 使用线程自动销毁:使用pthread_attr_setdetachstate函数设置线程属性为PTHREAD_CREATE_DETACHED,这使得线程在结束时自动释放资源,不需要手动调用pthread_join

    第二个问题:消费者线程不能及时消费生产者获取的用户输入

    对于消费者线程不能及时消费生产者获取的用户输入的问题,可以尝试以下解决方案:

    1. 使用缓冲区:在生产者线程获取用户输入后,将输入数据写入一个缓冲区,消费者线程则从缓冲区中获取数据进行消费。可以使用循环队列或者线程安全的队列来实现。

    2. 精确控制数据的同步:使用条件变量和互斥锁来控制数据的同步。在生产者线程写入缓冲区后,通过条件变量通知消费者线程可读取数据,消费者线程在读取数据前等待条件变量,以确保数据的及时性。

    3. 调整缓冲区大小或增加线程数量:如果消费者线程不能及时消费生产者获取的用户输入,可能是由于缓冲区过小或消费者线程数量不足导致的。可以尝试增加缓冲区大小或增加消费者线程数量,以提高消费速度。

    这是修改后的正确代码:

    // 修改ConsumerThread函数
    void *ConsumerThread(void *arg) {
      queue *cb = (queue *)arg;
      char item;
      while (1) {
        pthread_mutex_lock(&cb->mutex);
        while (cb->count == 0) {
          if (!cb->running) {
            pthread_mutex_unlock(&cb->mutex);
            return NULL;
          }
          pthread_cond_wait(&cb->not_empty, &cb->mutex);
        }
        Dequeue(cb, &item);
        pthread_mutex_unlock(&cb->mutex);
    
        // 消费数据
        printf("读取到字符: %c\n", item);
      }
    }
    
    // 主函数中初始化互斥锁和条件变量
    int main() {
      // ...
      pthread_mutex_init(&buffer->mutex, NULL);
      pthread_cond_init(&buffer->not_empty, NULL);
      pthread_cond_init(&buffer->not_full, NULL);
      
      // ...
    }
    
    // 修改producerThread中发出信号的时机
    void *producerThread(void *arg) {
      // ...
      
      // 在写入数据后发出信号
      pthread_mutex_lock(&cb->mutex);
      cb->count++;
      pthread_cond_signal(&cb->not_empty);
      pthread_mutex_unlock(&cb->mutex);
      
      // ...
    }
    
    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月28日
  • 创建了问题 6月2日

悬赏问题

  • ¥15 在matlab中Application Compiler后的软件无法打开
  • ¥15 想问一下STM32创建工程模板时遇到得问题
  • ¥15 Fiddler抓包443
  • ¥20 Qt Quick Android 项目报错及显示问题
  • ¥15 而且都没有 OpenCVConfig.cmake文件我是不是需要安装opencv,如何解决?
  • ¥15 oracleBIEE analytics
  • ¥15 H.264选择性加密例程
  • ¥50 windows的SFTP服务器如何能批量同步用户信息?
  • ¥15 centos7.9升级python3.0的问题
  • ¥15 安装CentOS6时卡住