0

I wrote a simple task like the following. It prints a string, increments the global variable glob, and returns its value, through the pthread_exit, to the pthread_join.

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

int glob = 0;

void *task()
{
    printf("I am a simple thread.\n");
    glob++;
    pthread_exit((void*)&glob);
}

int main()
{
pthread_t   tid;
int         create = 1;
void        **ppvglob;


    create = pthread_create(&tid, NULL, task, NULL);
    if (create != 0)    exit(EXIT_FAILURE);
    
    pthread_join(tid, ppvglob);
    
    int **ppv = (int**)ppvglob;
    printf("Variabile globale restituita alla terminazione del thread: %d\n", **ppv);                   
    
    return(0);
}

The compiler gives me the error:

main.c: In function ‘main’:
main.c:29:2: warning: ‘ppvglob’ may be used uninitialized in this function [-Wmaybe-uninitialized]
   29 |  pthread_join(tid, ppvglob);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~

Could you tell me the reason please?

Gennaro Arguzzi
  • 769
  • 1
  • 14
  • 27
  • Your pthread callback should have the format `void* f (void*)` and nothing else. Functions that return a value must actually `return` it too. – Lundin Jul 06 '20 at 09:07

3 Answers3

2

When doing:

pthread_join(tid, ppvglob);

because you never initialized ppvglob it is normal the compiler protest, but in fact you must replace:

void        **ppvglob;
....
pthread_join(tid, ppvglob);

by:

void        *pvglob;
....
pthread_join(tid, &pvglob);

then of course:

int **ppv = (int**)ppvglob;
printf("Variabile globale restituita alla terminazione del thread: %d\n", **ppv);                   

by:

int *pv = (int*)pvglob;
printf("Variabile globale restituita alla terminazione del thread: %d\n", *pv);

So having:

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

int glob = 0;

void *task()
{
    printf("I am a simple thread.\n");
    glob++;
    pthread_exit((void*)&glob);
}

int main()
{
  pthread_t   tid;
  int         create = 1;
  void        *pvglob;


  create = pthread_create(&tid, NULL, task, NULL);
  if (create != 0)    exit(EXIT_FAILURE);
    
  pthread_join(tid, &pvglob);
    
  int *pv = (int*)pvglob;
  printf("Variabile globale restituita alla terminazione del thread: %d\n", *pv);                   
    
  return(0);
}

Compilation and execution:

% gcc -Wall c.c -lpthread
% ./a.out
I am a simple thread.
Variabile globale restituita alla terminazione del thread: 1

that print 1 because this is the value of glob

bruno
  • 32,421
  • 7
  • 25
  • 37
  • Hello @bruno, could you explain me how come &pvglob is initialized please? I never used it before and the pthread_exit returns a void*, instead &pvglob is a void**. Maybe the pthread_exit inside makes a convertion from void* to void** and pass it to the pthread_join? – Gennaro Arguzzi Jul 06 '20 at 10:09
  • @GennaroArguzzi *pvglob* is set with the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit), if the target thread was canceled, then by PTHREAD_CANCELED ( see https://man7.org/linux/man-pages/man3/pthread_join.3.html ). So in your case you will get the value of *glob* – bruno Jul 06 '20 at 10:25
  • @GennaroArguzzi there is no conversion from `void**` to `void*`, the second argument of `pthread_join` is a pointer to allow the function to set the value, in that case the pointer point to a `void*` because this is the type return by the toplevel function of the thread / set by `pthread_exit`. Supposing the toplevel function of a thread return an `int` and then `pthread_exit` get an `int` to be consistent then `pthread_join` has to get a `int*` – bruno Jul 06 '20 at 10:48
  • I've only a doubt: why does the compiler tell that the ‘ppvglob’ may be used uninitialized? It is uninitialized because i never used it before. – Gennaro Arguzzi Jul 07 '20 at 15:19
  • @GennaroArguzzi it is uninitialized because you use its value before to set it. `void **ppvglob;` defines *ppvglob* without initializing it. In case it is a global variable it is initialized by NULL by default, but in your case it is a local variable so no default initialization – bruno Jul 07 '20 at 15:21
  • @GennaroArguzzi but giving its address (`&pvglob`) its value is not used at that level and the fact it is not initialized is not relevant => no warning – bruno Jul 07 '20 at 15:25
0

pthread_join() has a void ** parameter because it needs to update an existing void *.
It is the same logic as providing and int * to scanf("%d", ...): to update an existing int you need to provide its address.
In the general case, when a C function has to update an existing Type, then it needs a Type * parameter.

In any case, you don't just declare an uninitialised Type * but provide the address (&) of an existing Type.
So here, you need to take the address of an existing void * so that the parameter is initialised to a location where a void * actually stands.

prog-fh
  • 13,492
  • 1
  • 15
  • 30
0

The idea here is to have a void *...

void * glob;

...and to pass its address to pthread_join() so the function can make it point to the "return" value...

pthread_join(tid, &glob);

This "making it point to the 'return' value" requires pthread_join() to dereference its parameter...

*glob = /* whatever */;

...so that your glob will have changed it's value.

What you did was declaring...

void ** glob;

...which means that your call of...

pthread_join(tid, glob);

...will pass an uninitialized value to pthread_join() (making dereferencing it undefined behavior), and also mean that your glob will remain uninitialized, making your...

int **ppv = (int**)ppvglob;
printf("Variabile globale restituita alla terminazione del thread: %d\n", **ppv);                   

...undefined behavior as well.

This should work:

void * glob;

/* ... */

pthread_join(tid, &glob);

int * v = (int*)glob;
printf("Variabile globale restituita alla terminazione del thread: %d\n", *v);                   

(And, please pretty please, don't use System Hungarian notation... it's so bad even Microsoft stopped using it...)

DevSolar
  • 67,862
  • 21
  • 134
  • 209