0

Я делаю одну проблему с производителем-одним потребителем с двумя потоками в 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; 
} 
+0

Где в программе происходит segfault? –

+0

Вы должны проверить возвращаемое значение 'malloc'. Если он равен нулю, вы потеряли память. –

+0

@PaulOgilvie: Я не думаю, что 20K очень маленькие структуры будут исчерпывать память, даже если никто из них никогда не освобождается. –

ответ

3

Вам необходимо вернуться к своей блокировке; вы только приобретаете блокировки в начале каждого производителя &, а затем только разблокируйте их (повторно!), что означает, что дальнейшая синхронизация не происходит. Чем дольше работает ваша программа, тем более вероятно, что эта нехватка синхронизации приведет к отключению вашей программы.

+1

В дополнение к этому, вы также должны прочитать некоторые о «занятом ожидании» и о том, как этого избежать. – johni

+1

@SukhmanWaraich Ошибка при попытке разблокировать мьютекс, который уже разблокирован. Помещение вызова 'pthread_mutex_unlock' в цикле, как у вас есть, приведет только к неприятностям: https://linux.die.net/man/3/pthread_mutex_lock – yano

+1

Как сказал @johni. В частности, здесь может быть хорошим вариантом, или пара семафоров. –

0

Я думаю, что ваш замок должен быть:

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 на глобальную переменную, только манипулируйте им при блокировке.)

+0

Спасибо, Пол. я понял – wander