Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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 :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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;
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading