Tuesday, April 5, 2022

[SOLVED] segFault on return from pthread_join

Issue

I am implementing a stack pool to do some basic arithmetic in a specific number of threads.

here is the code:

int add(int a, int b) {return a+b;}
int sub(int a, int b) {return a-b;}
int mul(int a, int b) {return a*b;}
sem_t sem_ops;
void* compute(void* arg){
    Args *args = arg;
    Operation* op = args->operation;
    printOP(*op);
    int * value = malloc ( sizeof ( int ) ) ;
    * value = op->op(op->a, op->b);
    args->is_complete = true;
    sem_post(&sem_ops);
    return value;
}
void push(Operation op , Queue* q){
    q->operations[++(q->last)] = op;
}
Operation *pop(Queue *q){
    q->first++;
    return &q->operations[q->first];
}
int size(Queue *q){
    return q->last - q->first;
}
               
bool read_operations(char* filename, Queue* ops){
    printf("reading from file %s\n",filename);
    FILE *fp = fopen(filename, "r");
    if(fp == NULL ) 
    {
        printf("couldnt open");
        return false;
    }
    int id,a,b;
    while(!feof(fp)){
        fscanf(fp,"%d %d %d\n",&id,&a,&b);
        Operation op;
        op.a = a;
        op.b = b;
        switch (id){
            case 0:
                op.op = add;
                break;
            case 1:
                op.op = sub;
                break;
            case 2:
            default:
                op.op =mul;
                break;
        }
        push(op,ops);
    }
    return true;
}
ArrayList* execute_thread_pool(char* filename, int poolSize){
    sem_init(&sem_ops,0,poolSize);
    //init return value
    ArrayList* retval =malloc(sizeof(ArrayList));
    int res [ TOTAL_OP_COUNT];
    retval->results = res;
    retval->count = 0;
    // populate Q
    Queue q;
    Operation ops[TOTAL_OP_COUNT];
    q.first = 0;
    q.last = 0;
    q.max = TOTAL_OP_COUNT;
    q.operations = ops;
    read_operations(filename,&q);
    // thread tids
    pthread_t threads[TOTAL_OP_COUNT];
    //args for each thread
    Args args[TOTAL_OP_COUNT];
    int* result= NULL;
    for(int i =0; i<poolSize; ++i){
        sem_wait(&sem_ops);
        args[i].operation = pop(&q);
        args[i].is_complete=false;
        pthread_create(&threads[i],NULL, compute,&args[i]);
    }
    for(int i =0; i<poolSize; ++i){
        if(args[i].is_complete){
            pthread_join(threads[i],(void**) result);
            res[i] = *result; // line 88
        }else --i;
    }
    return retval;
}

and the structs typedefs:

typedef struct _Operation{
    int(*op) (int, int);
    int a;
    int b;
} Operation;
typedef struct _Args{
    Operation* operation;
    bool is_complete;
}Args;
typedef struct _Queue{
    Operation* operations;
    int last;
    int first;
    int max;
}Queue;

I tried using malloc at a few different places, but can't run away from segfault. this is the content of the main function:

    ArrayList *al =malloc(sizeof(ArrayList)) ;
    al = execute_thread_pool("bob.txt", 4);

in gdb the bt is as follow:

#0  0x0000555555555762 in execute_thread_pool (filename=0x555555556004 "bob.txt", poolSize=4) at pool.c:88
#1  0x00005555555552db in main (argc=1, argv=0x7fffffffda68) at main.c:5

I've been on this for a few hours, tried multiple ways, tried without semaphores and using not so fun loops and yet the same result. can anyone help me spot the issue?


Solution

You misunderstand the pthread_join call and how emulating pass-by-reference work in works.

You are supposed to pass a pointer to an int * variable, using the pointer-to operator &:

pthread_join(threads[i], &result);

You should also remember to free the pointer result, or you will have a memory leak.



Answered By - Some programmer dude
Answer Checked By - Senaida (WPSolving Volunteer)