【问题标题】:producer-consumer c - segmentation fault for bigger values生产者-消费者 c - 较大值的分段错误
【发布时间】:2017-02-11 15:46:38
【问题描述】:

我正在用 c 中的两个线程解决一个生产者一消费者的问题。我使用一个共享链表来做到这一点,生产者在其中放置一些东西,而消费者从同一个列表中获取它。 我必须使用 2 个值 N 和 B 运行我的代码(N 是要传输的数据的大小,B 是共享链表的最大大小)。 (./thread-a1 N B) 此代码对于小值运行良好。但是,对于 N = 20,000 和 B = 16,它给出分段错误:11 我无法弄清楚为什么会这样。请帮忙

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

struct job
{
    int data;
    struct job* next;
};

struct job* head;
int maxSize;
int n;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

int getCount()
{
    int count = 0;
    struct job* p = head;
    while(p != NULL)
    {
        p = p -> next;
        count++;
    }
    return count;
}

void Insert(int x)
{

    struct job* temp = (struct job*)malloc(sizeof(struct job));
    temp -> data = x;
    if (head == NULL)
    {
        temp -> next = NULL;
    }
    else
    {
        temp -> next = head;
    }
    head = temp;
}

void Delete()
{

    struct job *toDelete, *secondLastNode;

    if(head == NULL)
    {

    }
    else
    {
        toDelete = head;
        secondLastNode = head;


        while(toDelete->next != NULL)
        {

            secondLastNode = toDelete;
            toDelete = toDelete->next;
        }
        printf("%d, ", toDelete -> data);

        if(toDelete == head)
        {
            free(toDelete);
            head = NULL;
        }
        else
        {
            secondLastNode->next = NULL;
            free(toDelete);
        }

    }
}

void* producer(void* arg)
{
    pthread_mutex_lock(&m);
    head = NULL; 

    int i;
    for (i = 0; i<n; i++)
    {

        while(getCount() >= maxSize)
        {
            pthread_mutex_unlock(&m);
        }
        Insert(i);
    }

    return NULL;
}

void* consumer(void* arg)
{
    pthread_mutex_lock(&m);
    int i;
    for (i=0; i<n; i++)
    {
        while(getCount() <= 0)
        {
            pthread_mutex_unlock(&m);   
        }
        Delete();
    }


    return NULL;
}

int main(int argc, char *argv[])
{

    struct timeval start_init, end_init;
    gettimeofday(&start_init, NULL);
    n = atoi(argv[1]);
    maxSize = atoi(argv[2]);

    pthread_t thread1;
    pthread_t thread2;
    gettimeofday(&end_init, NULL);
    printf("Time elapsed for initialization is: %ld\n", 
        (long)(end_init.tv_sec*1000000 + end_init.tv_usec) -    (start_init.tv_sec*1000000 + start_init.tv_usec));

    struct timeval start_trans, end_trans;
    gettimeofday(&start_trans, NULL);
    pthread_create(&thread1, NULL, &producer, NULL);
    pthread_create(&thread2, NULL, &consumer, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    gettimeofday(&end_trans, NULL);
    printf("Time elapsed for transmission is: %ld\n", 
        (long)(end_trans.tv_sec*1000000 + end_trans.tv_usec) - (start_trans.tv_sec*1000000 + start_trans.tv_usec));


    return 0;
}

【问题讨论】:

  • 程序中的什么地方发生了段错误?
  • 你应该检查malloc的返回值。如果为零,则表示内存不足。
  • @PaulOgilvie:我不认为 20K 非常小的结构会耗尽内存,即使它们都没有被释放。
  • @ScottHunter:有时在它开始运行时,或者有时在运行之间
  • @PaulOgilvie:我添加了一个条件语句,如果 malloc 返回 0,则程序返回。但是,故障依旧发生

标签: c linux multithreading segmentation-fault producer-consumer


【解决方案1】:

我认为你的锁定应该是:

void* producer(void* arg)
{
    int i;
    for (i = 0; i<n; i++)
    {
        pthread_mutex_lock(&m);
        while(getCount() >= maxSize)
        {
            pthread_mutex_unlock(&m);   // allow consumer to acquire lock
            pthread_mutex_lock(&m);     // re-acquire lock
        }
        Insert(i);
        pthread_mutex_lock(&m);
    }
    return NULL;
}

void* consumer(void* arg)
{
    int i;
    for (i=0; i<n; i++)
    {
        pthread_mutex_lock(&m);
        while(getCount() <= 0)
        {
            pthread_mutex_unlock(&m);   // allow producer to acquire lock  
            pthread_mutex_lock(&m);     // re-acquire lock
        }
        Delete();
        pthread_mutex_lock(&m);
    }
    return NULL;
}

请注意,所有操作,包括getCount,都必须在获得锁的情况下完成。 (也可以考虑将getCount 替换为全局变量;仅在锁定时对其进行操作。)

【讨论】:

  • 谢谢保罗。我明白了
【解决方案2】:

您需要重新访问您的锁定;您只在每个生产者和消费者开始时获取锁,然后从那时起只解锁它们(重复!),这意味着不会发生进一步的同步。您的程序运行的时间越长,这种缺乏同步的情况就越有可能使您的程序出错。

【讨论】:

  • 除此之外,您还应该阅读一些关于“忙于等待”以及如何避免它的内容。
  • @SukhmanWaraich 尝试解锁已解锁的互斥锁是错误的。将pthread_mutex_unlock 调用循环调用只会导致麻烦:linux.die.net/man/3/pthread_mutex_lock
  • 正如@johni 所说。特别是,条件变量在这里是一个不错的选择,或者可能是一对信号量。
  • @ScottHunter:即使我把所有的锁都去掉了,也会出现错误
  • 不要移除锁;正确使用它们(或其他机制)。
猜你喜欢
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多