Gorka G Gorka G - 2 months ago 30
C Question

Casting and Argument Warnings

I have the following code, compiles and executes without errors but the compiler shows some warnings that I would like to "solve".

Thats my code:

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

typedef struct s_Barrier{
sem_t sEntry, sMutEx, sExit;
int nTaskInBarrier;
}Barrier;

void createTasks(pthread_t threads[]);
void task(void *arg);
void initBarrier(Barrier *pb, int n);
void destroyBarrier(Barrier *pb);
void waitInBarrier(Barrier *pb);


Barrier barrier;
int nTask = 5;


int main(void) {
pthread_t threads[nTask];

initBarrier(&barrier,nTask);
createTasks(threads);
destroyBarrier(&barrier);

return 0;
}

void createTasks(pthread_t threads[]){
int i;

for(i = 0; i < nTask; i++){
pthread_create(&threads[i], NULL, task, (void*)i);
}

for(i = 0; i < nTask; i++){
pthread_join(threads[i], NULL);
}
}

void initBarrier(Barrier *pb, int n){
pb->nTaskInBarrier = 0;

sem_init(&pb->sEntry,0,n);
sem_init(&pb->sExit,0,1);
sem_init(&pb->sMutEx,0,1);
}

void destroyBarrier(Barrier *pb){
sem_destroy(&pb->sEntry);
sem_destroy(&pb->sExit);
sem_destroy(&pb->sMutEx);
}

void task(void *arg){
int i = (int) arg;
while(1){
printf("I'm thread %d\n",i);
waitInBarrier(&barrier);
}
}

void waitInBarrier(Barrier *pb){
int x;
int i;

sem_wait(&pb->sEntry);
sem_wait(&pb->sMutEx);

x = ++pb->nTaskInBarrier;

sem_post(&pb->sMutEx);

if(x < nTask){
sem_wait(&pb->sExit);
}else{
for(i = 0; x < nTask ; i++){
sem_post(&pb->sExit);
}
}

sem_wait(&pb->sMutEx);

x = --pb->nTaskInBarrier;

sem_post(&pb->sMutEx);

if(x == 0){
for(i = 0; x < nTask ; i++){
sem_post(&pb->sEntry);
}
}

}


When I compile using the "gcc -o Barrier 3.4Barrier.c -pthread" get the following Warnings.

3.4Barrier.c: In function ‘createTasks’:
3.4Barrier.c:47:43: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
pthread_create(&threads[i], NULL, task, (void*)i);
^
3.4Barrier.c:47:37: warning: passing argument 3 of ‘pthread_create’ from incompatible pointer type [-Wincompatible-pointer-types]
pthread_create(&threads[i], NULL, task, (void*)i);
^
In file included from 3.4Barrier.c:13:0:
/usr/include/pthread.h:233:12: note: expected ‘void * (*)(void *)’ but argument is of type ‘void (*)(void *)’
extern int pthread_create (pthread_t *__restrict __newthread,
^
3.4Barrier.c: In function ‘task’:
3.4Barrier.c:70:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
int i = (int) arg;

Answer

The first problem is that task should return void*, not void, as specified by the prototype of pthread_create:

void* task(void *arg) {
    // ...
    return NULL;
}

This is easily solved.

The second problem is that you should not pass i this way - You should not cast an int to a void*. One way to pass i to task would be to allocate a small space of memory and use it1:

for(i = 0; i < nTask; i++){
    int *pi = malloc(sizeof(int));
    if (pi == NULL) { 
        // Something wrong...
    }
    *pi = i;
    pthread_create(&threads[i], NULL, task, pi);
}

And:

void* task(void *arg){
    int i = *(int*)arg; // Cast to `int*` and then dereference.
    free(arg); // Don't forget this!
    while(1){
        printf("I'm thread %d\n",i);
        waitInBarrier(&barrier);
    }
    return NULL;
}

1 Do not try to pass (void*)&i directly to pthread_create because there is no guarantee that *(int*)arg will be evaluated before the increment in the for loop so you might get some weird behavior where i is changed before you read its value.

Comments