使用信号量的生产者和消费者中的分段错误(核心已转储)

时间:2018-09-25 14:17:40

标签: c linux consumer producer

我正在学习Linux系统编程,所以我只是尝试编写一个非常普通的程序,即生产者和使用者。我使用信号量机制来实现我的代码。不幸的是,我遇到了分段错误,但我确实找不到我哪里错了。希望有人能帮助我,谢谢。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>

sem_t sem_consumer;
sem_t sem_producer;

typedef struct node
{   
    int data;
    struct node *next;
} Node;

Node * head = NULL;

void * producer(void *arg)
{
    while (1)
    {
        sem_wait(&sem_producer);
        Node *ptr = (Node *)malloc(sizeof(Node));
        ptr->data = rand() % 1000;
        printf("++++++ producer: %lu, %d\n", pthread_self(), ptr->data);
        ptr->next = head;
        head = ptr;
        sem_post(&sem_consumer);
    }

    return NULL;
}

void * consumer(void * arg)
{
    while (1)
    {
        sem_wait(&sem_consumer);
        Node *pdel = head;
        head = head -> next;
        printf("------ consumer: %lu, %d\n", pthread_self(), pdel->data);
        free(pdel);
        sem_post(&sem_producer);
    }

    return NULL;
}

int main(int argc, char *argv[])
{
    sem_init(&sem_consumer, 0, 0);
    sem_init(&sem_producer, 0, 3);

    pthread_t pthid[2];

    pthread_create(&pthid[0], NULL, producer, NULL);
    pthread_create(&pthid[1], NULL, consumer, NULL);

    for (int i = 0; i < 2; i++)
    {
        pthread_join(pthid[i], NULL);
    }

    sem_destroy(&sem_consumer);
    sem_destroy(&sem_producer);

    return 0;
}

2 个答案:

答案 0 :(得分:2)

sem_init(&sem_producer, 0, 3);

sem_producer信号量初始化为3,从而允许生产者线程和消费者线程同时访问

之类的代码。
ptr->next = head;
head = ptr;

Node *pdel = head;
head = head -> next;
printf("------ consumer: %lu, %d\n", pthread_self(), pdel->data);
free(pdel);

您的链表没有受到信号灯的正确保护。那是比赛条件。

sem_producer初始化为1将纠正竞态条件:

sem_init(&sem_producer, 0, 1);

我可能还没有发现其他错误。

答案 1 :(得分:2)

我认为主要问题是:

  • 您只有一种资源-head
  • 您使用两个独立的信号灯-sem_producersem_consumer
  • 对它进行“ 保护

信号量用于表示“ 您可以拿东西”或“ 您可以拿东西”来控制资源的使用-例如,如果要确保列表的深度永远不会超过三个对象。当生产者/使用者线程具有不同的执行时间时,这一点尤其重要。如果您对生产消费者可能永远无法跟上的物品负荷不太感兴趣,那么可以完全删除sem_producer

Mutexes(“ 互斥”)用于确保两个线程不会同时处理一个对象。我建议您在信号量旁边的指针操作周围使用互斥体。

pthread_mutex_t mux;
void *producer(void *arg) {
    while (1) {
        sem_wait(&sem_producer);

        /* gather data */

        pthread_mutex_lock(&mux);
        p_new->next = head;
        head = p_new;
        pthread_mutex_unlock(&mux);

        sem_post(&sem_consumer);
    }

    return NULL;
}
void *consumer(void *arg) {
    while (1) {
        sem_wait(&sem_consumer);

        pthread_mutex_lock(&mux);
        p_next = head;
        if (p_next != NULL) {
            head = p_next->next;
        }
        pthread_mutex_unlock(&mux);

        /* skip if there isn't actually a new item */
        if (p_next != NULL) {
            /* do processing and discard */
        }

        sem_post(&sem_producer);
    }

    return NULL;
}

别忘了给pthread_mutex_init()pthread_mutex_destroy()打电话。