【发布时间】:2019-08-19 21:05:57
【问题描述】:
我正在尝试使用条件变量来实现生产者消费者,以便了解同步。我正在使用github 来指导我并解决了一些段错误,但现在看来我的消费者从未被执行或陷入僵局。我不确定可能是什么错误。我在生产者中包含了 printf 语句,以在每次运行时执行,并且它完成了在 messages.txt 中生成小于 5 的任何字符串。消费者虽然没有并且陷入死锁。
#define max 5
int par = 0;
// Data structure for queue
struct queue
{
char *items; // array to store queue elements
int maxsize; // maximum capacity of the queue
int front; // front points to front element in the queue (if any)
int rear; // rear points to last element in the queue
int size; // current capacity of the queue
pthread_mutex_t mutex; // needed to add/remove data from the buffer
pthread_cond_t can_produce; // signaled when items are removed
pthread_cond_t can_consume; // signaled when items are added
};
// Utility function to initialize queue
struct queue* newQueue(int size)
{
struct queue *pt = NULL;
pt = (struct queue*)malloc(sizeof(struct queue));
pt->items = (char*)malloc(size * sizeof(char));
pt->maxsize = size;
pt->front = 0;
pt->rear = -1;
pt->size = 0;
pthread_mutex_init(&pt->mutex, NULL);
pthread_cond_init(&pt->can_produce, NULL);
pthread_cond_init(&pt->can_consume, NULL);
return pt;
}
// Utility function to return the size of the queue
int size(struct queue *pt)
{
return pt->size;
}
// Utility function to check if the queue is empty or not
int isEmpty(struct queue *pt)
{
return !size(pt);
}
// Utility function to return front element in queue
char front(struct queue *pt)
{
if (isEmpty(pt))
{
//printf("UnderFlow\nProgram Terminated\n");
}
return pt->items[pt->front];
}
// Utility function to add an element x in the queue
void enqueue(struct queue *pt, char x)
{
if (size(pt) == pt->maxsize)
{
//printf("OverFlow\nProgram Terminated\n");
}
//printf("Inserting %c\t", x);
pt->rear = (pt->rear + 1) % pt->maxsize; // circular queue
pt->items[pt->rear] = x;
pt->size++;
//printf("front = %c, rear = %c\n", pt->front, pt->rear);
}
// Utility function to remove element from the queue
void dequeue(struct queue *pt)
{
if (isEmpty(pt)) // front == rear
{
//printf("UnderFlow\nProgram Terminated\n");
}
//printf("Removing %c\t", front(pt));
pt->front = (pt->front + 1) % pt->maxsize; // circular queue
pt->size--;
//printf("front = %d, rear = %c\n", pt->front, pt->rear);
}
void consumer_f(void *arg)
{
struct queue *pt = (struct queue*)arg;
while (par==0 && !isEmpty(pt))
{
pthread_mutex_lock(&pt->mutex);
if (pt->size == 0)
{ // empty
// wait for new items to be appended to the buffer
pthread_cond_wait(&pt->can_consume, &pt->mutex);
}
printf("%c", pt->front);
dequeue(pt);
pthread_cond_signal(&pt->can_produce);
pthread_mutex_unlock(&pt->mutex);
}
}
void producer_f(void *arg)
{
struct queue *pt = (struct queue*)arg;
char tmp;
FILE *fp;
fp = fopen("messages.txt", "r");
if (fp == NULL)
{
//fprintf(stderr, "error opening messages.txt");
return -1;
}
while ((tmp = fgetc(fp)) != EOF)
{
pthread_mutex_lock(&pt->mutex);
if (pt->size == max)
pthread_cond_wait(&pt->can_produce, &pt->mutex);
enqueue(pt, tmp);
printf("sent");
pthread_cond_signal(&pt->can_consume);
pthread_mutex_unlock(&pt->mutex);
}
par = 1; //denotes EOF for consumer */
}
int main()
{
printf("nop");
struct queue *pt = newQueue(5);
pthread_t producer;
pthread_t consumer;
printf("got here");
if (pthread_create(&producer, NULL, &producer_f, pt))
{
//fprintf(stderr, "Error creating producer thread\n");
return -1;
}
if (pthread_create(&consumer, NULL, &consumer_f, pt))
{
//fprintf(stderr, "Error creating consumer thread\n");
return -1;
}
if (pthread_join(producer_f, NULL))
{
//fprintf(stderr, "Error joining proucer thread\n");
return -1;
}
if (pthread_join(consumer_f, NULL))
{
//fprintf(stderr, "Error joinging consumer thread\n");
return -1;
}
return 0;
}
【问题讨论】:
-
不要使用
printf()。stdout如果引用交互式设备,则为行缓冲,否则为完全缓冲。由于并非所有调试-printf()s 都包含\n,因此无论如何您都应该调试到stderr。 -
另外,从多个线程对对象的非同步、非原子、非只读访问的未定义行为。
-
我已将所有调试 printf() 更改为 frpintf() 打印到 stderr。你是什么意思“从多个线程对对象的非同步、非原子、非只读访问的未定义行为。”编辑:您是在谈论在消费者和生产者中访问
int par吗? -
C11 标准草案 n1570:5.1.2.4 多线程执行和数据竞争 4 如果其中一个修改了内存位置,而另一个读取或修改了相同的内存位置,则两个表达式计算冲突. 25 如果一个程序在不同线程中包含两个相互冲突的操作,则该程序的执行包含数据竞争,其中至少一个不是原子的,并且两者都不会在另一个之前发生。任何此类数据竞争都会导致未定义的行为。
-
我有一个这样的文件库,你可以用它作为参考
标签: c pthreads deadlock race-condition producer-consumer