如何通过命令行参数设置数组大小?生产者消费者线程共享疑问
问题解答
1. 运行时确定缓冲区大小,必须用动态数组吗?
是的,你必须用动态内存分配(比如malloc)。因为固定大小的数组要求大小是编译时常量,而你的缓冲区大小是运行时通过命令行参数传入的,编译时无法确定,所以只能用动态分配。
你觉得“将数组大小关联到malloc分配的内存区域不太合理”其实是误解——malloc分配的内存是一块连续的、固定大小的区域,只要你在结构体里记录了buffSize,线程就可以通过这个值确定数组的边界,和固定大小数组的使用方式完全一致。动态分配只是内存的分配时机在运行时,本质上和固定数组一样是“固定大小”的缓冲区,只是内存不在栈上,而是在堆上。
所以你的思路没问题,用malloc是正确且必要的选择。
2. 为什么很多生产者消费者方案用全局缓冲区?
线程确实会共享父进程的所有内存(包括堆、全局数据区,每个线程只有自己的栈是独立的),所以全局缓冲区不是技术上的必需,更多是代码写法上的简化:
- 初学者写代码时,用全局变量可以避免在多个线程函数之间传递结构体指针,减少指针操作的复杂度;
- 早期的示例代码为了降低理解门槛,会用全局变量让逻辑更直观。
但从工程角度,用结构体封装共享数据(比如你的shared_info)并传递给线程,代码的模块化更好、耦合度更低,更容易维护和扩展,比全局变量更优。所以你现在的做法(用结构体传递)是更规范的,没必要改成全局变量。
修正后的代码
你的代码存在几个严重的错误(比如野指针、未定义变量、信号量未释放等),以下是修正后的版本:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <semaphore.h> #include <pthread.h> #include <stdbool.h> #include <time.h> //function declarations void* producer(void*); void* consumer(void*); typedef struct { sem_t mtx; sem_t empty; sem_t full; int *buff; int buffSize; int psTime; int csTime; // 新增:记录生产者/消费者的当前操作位置(环形缓冲区常用) int in; int out; } shared_info; int main (int argc, char*argv[]) { // 修正:给shr分配内存,避免野指针 shared_info *shr = malloc(sizeof(shared_info)); if (shr == NULL) { fprintf(stderr, "Failed to allocate shared info.\n"); exit(1); } pthread_t pro, con; if( argc != 4 ){ fprintf(stderr, "Incorrect number of arguments. Usage: ./program <buffSize> <psTime> <csTime>\n"); exit(1); } //grabbing input from command line arguments shr->buffSize = strtol(argv[1], NULL, 10); shr->psTime = strtol(argv[2], NULL, 10); shr->csTime = strtol(argv[3], NULL, 10); shr->in = 0; shr->out = 0; shr->buff = malloc(shr->buffSize * sizeof(int)); if (shr->buff == NULL) { fprintf(stderr, "Memory allocation failed for buffer.\n"); free(shr); return -1; } // 删掉无效代码:shr->buff[shr->buffSize]; // 修正:printf里的变量需用shr->前缀 printf("buffSize: %d psTime:%d csTime: %d\n", shr->buffSize, shr->psTime, shr->csTime); // 初始化信号量,第二个参数为0表示线程间共享 sem_init(&shr->mtx, 0, 1); sem_init(&shr->full, 0, 0); sem_init(&shr->empty, 0, shr->buffSize); // 初始化随机数种子 srand(time(NULL)); pthread_create(&pro, NULL, producer, shr); sleep(1); pthread_create(&con, NULL, consumer, shr); pthread_join(pro, NULL); pthread_join(con, NULL); printf("Main thread done.\n"); sem_destroy(&shr->mtx); sem_destroy(&shr->empty); sem_destroy(&shr->full); // 释放内存 free(shr->buff); free(shr); return 0; } //producer thread void *producer(void * arg){ // 修正:将参数转换为正确的结构体类型 shared_info *shr = (shared_info*)arg; while( true){ sem_wait(&shr->empty); sem_wait(&shr->mtx); // 生产随机整数(900-1000) int rand1 = rand()%101 + 900; shr->buff[shr->in] = rand1; printf("Produced: %d, stored at position %d\n", rand1, shr->in); shr->in = (shr->in + 1) % shr->buffSize; sem_post(&shr->mtx); sem_post(&shr->full); // 模拟生产时间 sleep(shr->psTime); } return NULL; } //Consumer thread void *consumer(void * arg){ shared_info *shr = (shared_info*)arg; while( true){ sem_wait(&shr->full); sem_wait(&shr->mtx); int val = shr->buff[shr->out]; printf("Consumed: %d, from position %d\n", val, shr->out); shr->out = (shr->out + 1) % shr->buffSize; sem_post(&shr->mtx); sem_post(&shr->empty); // 模拟消费时间 sleep(shr->csTime); } return NULL; }
内容的提问来源于stack exchange,提问作者Josue Nunez
相关产品推荐
相关产品推荐

