POSIX线程。为什么生产者消费者计划终止?

发布于 2025-01-27 16:21:45 字数 2679 浏览 1 评论 0原文

我尝试使用Posix线程(用于使用线程的库)编写一个简单的C生产者 - 消费者程序。

该代码具有从线程交换信息的全局队列。队列已经进行了测试,应正确工作。还涉及两个线程:

生产者。生成一个随机数并将其放在队列中; 消费者。从队列中检索一个数字,然后将其打印到屏幕上。

main.c


#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include "queue.h"

pthread_mutex_t mutex;
pthread_cond_t pcond;
pthread_cond_t ccond;

static const unsigned int X = 10;

void* producer(void* args)
{
    for (int i = 0; i < X; i++)
    {
        pthread_mutex_lock(&mutex);
        while (queue_is_full())
            pthread_cond_wait(&pcond, &mutex);
        if (queue_is_empty())
            pthread_cond_signal(&ccond);
        queue_enqueue(rand() % (9999 + 1 - 0) + 0);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

void* consumer(void* args)
{
    for (int i = 0; i < X; i++)
    {
        pthread_mutex_lock(&mutex);
        while (queue_is_empty())
            pthread_cond_wait(&ccond, &mutex);
        if (queue_is_full())
            pthread_cond_signal(&pcond);
        printf("%i", queue_dequeue());
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&pcond, NULL);
    pthread_cond_init(&ccond, NULL);
    
    pthread_t thProducer, thConsumer;
    pthread_create(&thProducer, NULL, producer, NULL);
    pthread_create(&thConsumer, NULL, consumer, NULL);
    
    pthread_join(thProducer, NULL);
    pthread_join(thConsumer, NULL);
    return 0;
}

此程序在启动时终止。消息 application.exe已停止工作。在启动程序后立即发出系统。如何修复该程序?

queue.c

#include "queue.h"
 
#define CAPACITY 2048
 
static int* queue;
static int head;
static int tail;
 
void queue_init()
{
    queue = malloc(CAPACITY * sizeof(int));
    head = -1;
    tail = 0;
}
 
void queue_enqueue(int value)
{
    if (queue_is_full())
        exit(1);
    queue[tail] = value;
    if (head == -1)
        head = 0;
    if (tail == CAPACITY - 1)
        tail = 0;
    else
        tail++;
}
 
int queue_dequeue()
{
    if (queue_is_empty())
        exit(1);
    int item = queue[head];
    if (head != CAPACITY - 1)
        head++;
    else
        head = 0;
    if (head == tail)
    {
        head = -1;
        tail = 0;
    }
    return item;
}
 
bool queue_is_full()
{
    return head == tail;
}
 
bool queue_is_empty()
{
    return head == -1;
}
 
int queue_size()
{
    if (head != -1)
    {
        return head < tail ? tail - head : (CAPACITY - head) + tail;
    }
    return 0;
}

I tried to write a simple C producer-consumer program using POSIX Thread, a library for working with threads.

The code has a global queue from where threads exchange information. The queue has been tested and should work correctly. There are also two threads involved:

Producer. Generates a random number and puts it in a queue;
Consumer. Retrieves a number from the queue and prints it to the screen.

main.c:


#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include "queue.h"

pthread_mutex_t mutex;
pthread_cond_t pcond;
pthread_cond_t ccond;

static const unsigned int X = 10;

void* producer(void* args)
{
    for (int i = 0; i < X; i++)
    {
        pthread_mutex_lock(&mutex);
        while (queue_is_full())
            pthread_cond_wait(&pcond, &mutex);
        if (queue_is_empty())
            pthread_cond_signal(&ccond);
        queue_enqueue(rand() % (9999 + 1 - 0) + 0);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

void* consumer(void* args)
{
    for (int i = 0; i < X; i++)
    {
        pthread_mutex_lock(&mutex);
        while (queue_is_empty())
            pthread_cond_wait(&ccond, &mutex);
        if (queue_is_full())
            pthread_cond_signal(&pcond);
        printf("%i", queue_dequeue());
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&pcond, NULL);
    pthread_cond_init(&ccond, NULL);
    
    pthread_t thProducer, thConsumer;
    pthread_create(&thProducer, NULL, producer, NULL);
    pthread_create(&thConsumer, NULL, consumer, NULL);
    
    pthread_join(thProducer, NULL);
    pthread_join(thConsumer, NULL);
    return 0;
}

This program terminates upon startup. The message Application.exe has stopped working. is issued by the system immediately after starting the program. How can I fix the program?

queue.c:

#include "queue.h"
 
#define CAPACITY 2048
 
static int* queue;
static int head;
static int tail;
 
void queue_init()
{
    queue = malloc(CAPACITY * sizeof(int));
    head = -1;
    tail = 0;
}
 
void queue_enqueue(int value)
{
    if (queue_is_full())
        exit(1);
    queue[tail] = value;
    if (head == -1)
        head = 0;
    if (tail == CAPACITY - 1)
        tail = 0;
    else
        tail++;
}
 
int queue_dequeue()
{
    if (queue_is_empty())
        exit(1);
    int item = queue[head];
    if (head != CAPACITY - 1)
        head++;
    else
        head = 0;
    if (head == tail)
    {
        head = -1;
        tail = 0;
    }
    return item;
}
 
bool queue_is_full()
{
    return head == tail;
}
 
bool queue_is_empty()
{
    return head == -1;
}
 
int queue_size()
{
    if (head != -1)
    {
        return head < tail ? tail - head : (CAPACITY - head) + tail;
    }
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

長街聽風 2025-02-03 16:21:45

GCC的-fsanitize = address找到直接问题立即调试器)。

AddressSanitizer:DEADLYSIGNAL
=================================================================
==1==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000401436 bp 0x7fbd0f7fde40 sp 0x7fbd0f7fde30 T2)
==1==The signal is caused by a READ memory access.
==1==Hint: address points to the zero page.
    #0 0x401436 in queue_dequeue /app/example.c:56
    #1 0x401596 in consumer /app/example.c:99
    #2 0x7fbd139c4608 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x8608)
    #3 0x7fbd138e9162 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x11f162)

因此,这是null在此行中的指针解除:

  int item = queue [head];
 

队列是由Queue_init ...初始化的。

gcc's -fsanitize=address finds the direct problem immediately (and so should every debugger).

AddressSanitizer:DEADLYSIGNAL
=================================================================
==1==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000401436 bp 0x7fbd0f7fde40 sp 0x7fbd0f7fde30 T2)
==1==The signal is caused by a READ memory access.
==1==Hint: address points to the zero page.
    #0 0x401436 in queue_dequeue /app/example.c:56
    #1 0x401596 in consumer /app/example.c:99
    #2 0x7fbd139c4608 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x8608)
    #3 0x7fbd138e9162 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x11f162)

So it's a NULL pointer dereference at this line:

int item = queue[head];

queue is initialized by queue_init ...which is never called.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文