Wrong argument cast in pthread_create

what I’m trying to do is send the integer value 0 to the function to use it as an index of my array. But instead of writing to patients[0], it writes to patients[1]. Any idea why?
I am simple looping from 0 to 1, just to see if it’s passing the value 0 correctly, passing i(0) to function, assign myArr[0] to something, but it assigns to myArr[1] instead.

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

typedef struct patient_info {
    pthread_t thread;
    char treatment;
    char department[20];
} patient;

patient patients[1000];

void* registration(void* arg)
{
    int p_num = *((int*)arg); // my array index that supposed to be 0

        if (rand() % 2 == 0)
        {
            patients[p_num].treatment = 'M';
        }
        else
        {
            patients[p_num].treatment = 'S';
        }

    return NULL;
}

int main(void)
{
    srand(time(NULL));

    for (size_t i = 0; i < 1; i++) // simple for loop to create my thread
    {
        if (pthread_create(&patients[i].thread, NULL, &registration, (void*)&i) != 0)
        {
            perror("There has been an error with pthread_create().");
            return 1;
        }
    }

    for (size_t j = 0; j < 1; j++)
    {
        if (pthread_join(patients[j].thread, NULL) != 0)
        {
            perror("There has been an error with the pthread_join().");
            return 2;
        }
    }

    for (size_t i = 0; i < 1000; i++) // make this loop to see where it is writing.
    {
        if (patients[i].treatment == 'M' || patients[i].treatment == 'S')
        {    
            printf("Treatment is: %c %d\n", patients[i].treatment, i);
        }        
    }
    return 0;
}

>Solution :

You are passing a pointer to i, so each thread points to the same i variable.

Thus, the threads race to get their value. (e.g.) threadA wants 0 and threadB wants 1. But, if the main task is fast enough both might see either 0 or 1. Thus, a conflict.

Also, in main, i is a size_t but in registration, it’s an int pointer. They are [probably] different sizes.

The solution is to pass i by value

pthread_create(&patients[i].thread, NULL, &registration, (void *) i)

And, in registration, we accept by value:

void *
registration(void *arg)
{
    size_t p_num = (size_t) arg;

    // ...

    return (void *) 0;
}

Here’s the corrected code:

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

typedef struct patient_info {
    pthread_t thread;
    char treatment;
    char department[20];
} patient;

patient patients[1000];

void *
registration(void *arg)
{
    // my array index that supposed to be 0
// NOTE/BUG: this uses the wrong size pointer and to prevent the race condition
// we want to accept by value
#if 0
    int p_num = *((int *) arg);
#else
    size_t p_num = (size_t) arg;
#endif

    if (rand() % 2 == 0) {
        patients[p_num].treatment = 'M';
    }
    else {
        patients[p_num].treatment = 'S';
    }

    return NULL;
}

int
main(void)
{
    srand(time(NULL));

    // simple for loop to create my thread
    for (size_t i = 0; i < 1; i++) {
        if (pthread_create(&patients[i].thread, NULL, &registration,
#if 0
            (void *) &i) != 0) {
#else
            (void *) i) != 0) {
#endif
            perror("There has been an error with pthread_create().");
            return 1;
        }
    }

    for (size_t j = 0; j < 1; j++) {
        if (pthread_join(patients[j].thread, NULL) != 0) {
            perror("There has been an error with the pthread_join().");
            return 2;
        }
    }

    // make this loop to see where it is writing.
    for (size_t i = 0; i < 1000; i++) {
        if (patients[i].treatment == 'M' || patients[i].treatment == 'S') {
            printf("Treatment is: %c %d\n", patients[i].treatment, i);
        }
    }

    return 0;
}

Since you’ve gone to the trouble of creating a patient struct, we can clean up the code a bit by using and passing around some pointers to that struct:

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

typedef struct patient_info {
    pthread_t thread;
    char treatment;
    char department[20];
} patient;

patient patients[1000];

void *
registration(void *arg)
{
    patient *pt = arg;

    if (rand() % 2 == 0) {
        pt->treatment = 'M';
    }
    else {
        pt->treatment = 'S';
    }

    return NULL;
}

int
main(void)
{
    srand(time(NULL));

    patient *pt;

    // simple for loop to create my thread
    for (size_t i = 0; i < 1; i++) {
        pt = &patients[i];

        if (pthread_create(&pt->thread, NULL, &registration, pt) != 0) {
            perror("There has been an error with pthread_create().");
            return 1;
        }
    }

    for (size_t j = 0; j < 1; j++) {
        pt = &patients[j];

        if (pthread_join(pt->thread, NULL) != 0) {
            perror("There has been an error with the pthread_join().");
            return 2;
        }
    }

    // make this loop to see where it is writing.
    for (size_t i = 0; i < 1000; i++) {
        pt = &patients[i];

        if (pt->treatment == 'M' || pt->treatment == 'S') {
            printf("Treatment is: %c %d\n", pt->treatment, i);
        }
    }

    return 0;
}

Leave a Reply