I am trying to create 1000000+ threads and have them add and remove elements from a queue. The queue has a size of 10 elements and when it's full and wants to add an element it waits for a signal from a Condition, same thing goes for when it's empty and trying to remove an element.
The code is working fine when I am creating 100000 threads, but it's giving me a segmentation fault when I try to add one or more zeroes.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define SIZE 10
long NBTHREADS = 1000000;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t notFull = PTHREAD_COND_INITIALIZER;
pthread_cond_t notEmpty = PTHREAD_COND_INITIALIZER;
long sum = 0;
typedef long element;
typedef struct queue{
    element data[SIZE];
    int front, rear;
}queue;
queue CreateQueue(){
    queue q;
    q.front = 1;
    q.rear = 0;
    return q;
}
queue list;
int isEmptyQueue(queue q) {
    return (q.front == (q.rear + 1) % SIZE);
}
int isFullQueue(queue q) {
    return (q.front == (q.rear + 2) % SIZE);
}
int EnQueue(queue *q,element e) {
    q->rear = (q->rear + 1) % SIZE;
    q->data[q->rear] = e;
    return 1;
}
int DeQueue(queue *q) {
    q->front = (q->front + 1) % SIZE;
    return 1;
}
int Front(queue q,element *e) {
    if (isEmptyQueue(q))return 0;
    *e = q.data[q.front];
    return 1;
}
void PrintQueue(queue q){
    element e;
    while(!isEmptyQueue(q) && Front(q, &e)){
        printf("%ld ", e);
        DeQueue(&q);
    }
    printf("\n");
}
void *addToList(void *num)
{
    long number = (long)num;
    pthread_mutex_lock(&lock);
    while(isFullQueue(list))
        pthread_cond_wait(¬Full, &lock);
    EnQueue(&list, number);
    pthread_cond_signal(¬Empty);
    sum++;
    pthread_mutex_unlock(&lock);
    pthread_exit(0);
}
void *deleteFromList()
{
    pthread_mutex_lock(&lock);
    while(isEmptyQueue(list))
        pthread_cond_wait(¬Empty, &lock);
    DeQueue(&list);
    pthread_cond_signal(¬Full);
    sum++;
    pthread_mutex_unlock(&lock);
    pthread_exit(0);
}
int main()
{
    list = CreateQueue();
    void *status;
    pthread_attr_t attr;
    pthread_t threads[NBTHREADS];
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    for(long i=0; i<NBTHREADS; i++)
    {
        long err;
        if(i<(NBTHREADS/2))
        {
            err = pthread_create(&threads[i], &attr, addToList, (void*)i);
        }else{
            err = pthread_create(&threads[i], &attr, deleteFromList, NULL);
        }
        if(err){
            printf("\nError Creating Thread...");
            exit(-1);
        }
    }
    pthread_attr_destroy(&attr);
    for(long i=0; i<NBTHREADS; i++)
    {
        long err = pthread_join(threads[i], &status);
        if(err)
            printf("\nFAILED TO JOIN MAIN WITH THREAD %ld", (long)status);
        else
            printf("\nsuccessfully joined");
    }
    printf("\nSum is: %ld", sum);
    PrintQueue(list);
    pthread_exit(NULL);
}
It's giving me this error:
Process returned -1073741571 (0xC00000FD)   execution time : 9.364 s
I am still new to multi-threading and parallel programming.
Maybe I am using the lock in a wrong place?
But the thing is, when I make the NBTHREADS variable 100000 or less, the program is executing fine and returning 0, and the queue is not printing anything (it's empty).
I can't tell where my problem is, help appreciated.
There may be other system limitations that prevents 1.000.000 threads but there is (most likely) a stack overflow problem involved.
In main you have:
pthread_t threads[NBTHREADS];
An array with automatic storage duration (often called "a local variable") is on typically systems stored in a fixed size memory block called a stack. If the size of the array exceeds the size of the stack, you have a stack overflow and your program won't work.
On my system 1.000.000 pthread_t is 8.000.000 bytes which is above the (default) stack size for my system. So such a program will fail on my system.
You can do (at least) 3 things:
Put the array variable in global space (kind of ugly solution)
Allocate the array using malloc
Increase the stack size if allowed on your system
For solution 1 do:
//long NBTHREADS = 1000000;
#define NBTHREADS 1000000
pthread_t threads_global[NBTHREADS];
int main()
{
    list = CreateQueue();
    void *status;
    pthread_attr_t attr;
    ////pthread_t threads[NBTHREADS];
    pthread_attr_init(&attr);
and update the code to use this new "ugly" variable name
For solution 2 do:
int main()
{
    list = CreateQueue();
    void *status;
    pthread_attr_t attr;
    pthread_t *threads = malloc(NBTHREADS * sizeof *threads);
    assert(threads != NULL);  // Or: if (threads == NULL) exit(1);
For solution 3:
Depends on your system
I would go for solution 2.
User contributions licensed under CC BY-SA 3.0