7

i'm working on gcc , i'm wondering if this is possible:

I have a function (NOTmain but aLocalFn) and I declare a local variable in it. Then I pass this local argument as a thread argument. is it doable? or there is the chance (depending on what is run first) that the aLocalVar will be lost before threadFunction is run and the reference idxPtr will be pointing to senselessness??

int *threadFunction(void *idxPtr){
    int rec_idx=(int) *idxPtr;

    //work in the thread with this variabel rec_idx
}

int aLocalFn(){
   int aLocalVar=returnsRecordIndex();

   pthread_create(&thread_id,&attr_detached,threadFunction, &aLocalVar)!=0)
   return 0;
}   

thank you for your help

hmjd
  • 120,187
  • 20
  • 207
  • 252
nass
  • 1,453
  • 1
  • 23
  • 38

5 Answers5

8

This code is incorrect. The function aLocalFn may return before the thread function starts executing. And so by the time the thread function reads the local variable, the scope of that variable may have ended.

What can confuse matters is that this code may very well appear to work, at least some of the time. However, it is incorrect and you should use heap allocated memory instead.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Just want to confirm: If I change the code to `pthread_create(&thread_id,NULL,threadFunction, &aLocalVar)`, and `pthread_join` somwhere after `pthread_create`, would that be fine? – Rick Sep 26 '21 at 15:55
4

It's doable, but it's not done in the code in your question. You will have to add a signal variable to indicate when the new thread is done using the variable. Then your outer function can return.

static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t signal = PTHREAD_COND_INITIALIZER;
int done;

int *threadFunction(void *idxPtr){
    int rec_idx=(int) *idxPtr;

    pthread_mutex_lock(&lock);
    done = 1;
    pthread_cond_signal(&signal);
    pthread_mutex_unlock(&lock);

    //work in the thread with this variabel rec_idx
}

int aLocalFn(){
    int aLocalVar=returnsRecordIndex();

    done = 0;
    pthread_create(&thread_id,&attr_detached,threadFunction, &aLocalVar)!=0)
    pthread_mutex_lock(&lock);
    while (!done)
        pthread_cond_wait(&signal, &lock);
    pthread_mutex_unlock(&lock);
    return 0;
}   

Note that this example code is itself not thread safe (if multiple threads call aLocalFn).

This does complicate the code, and locking is expensive. So in most cases you're probably better off storing the data in the heap and letting the new thread or pthread_join code free it.

Per Johansson
  • 6,697
  • 27
  • 34
  • 2
    Yes, this does indeed do the job, but it's surely not a good solution. I trust you would not recommend this over, say, heap allocation. – David Heffernan May 21 '12 at 10:17
  • I try to not make assumptions beyond what's stated in the question. I've had need for similar code in the case where `aLocalFn` is a callback and the data will be freed automatically when it returns. For a simple `int`, this is not really a good solution, no. – Per Johansson May 21 '12 at 10:35
  • +1 for a 'different' answer. But, I also do not agree that this is a good solution as it necessitates unnecessary creation of conditional variables and hold the creator thread resources waiting the created to finish. – Jay May 21 '12 at 12:32
  • This can be an acceptable solution if you know the code will only generate exactly 1 instance of the threadFunction. – nass May 26 '12 at 10:22
4

your code has a life-time issue with "aLocalVar" if you just want to pass an integer, here is a non-portable way to do it. it does not work on some platforms, but you are not likely to encounter those.

void threadFunction ( void * idxptr ) {
    int rec_idx = (int) idxptr;
    ....
}

int rec_idx = returnsRecordIndex();
pthread_create (&thread1, &attr_detached, (void *) &threadFunction, (void *)rec_idx);
pizza
  • 7,296
  • 1
  • 25
  • 22
2

@pizza's answer is what I'd do. Another way for you to do it would be to use malloc/free as @David hinted at. I would certainly do this over the wait loop proposed in other answers here.

int *threadFunction(void *idxPtr){
    int rec_idx = *(int *)idxPtr;
    // free up our int buffer
    free(idxPtr);
    ...
}

int aLocalFn(){
    int aLocalVar = returnsRecordIndex();
    // allocate some space for our int
    int *intBuf = (int *)malloc(sizeof(int));
    *intBuf = aLocalVar;
    pthread_create(&thread_id,&attr_detached,threadFunction, intBuf)!=0)
    return 0;
}   
Gray
  • 115,027
  • 24
  • 293
  • 354
1

Whenever you are passing variables to a thread function, it is your job to ensure that the variable remains alive and valid till the thread function is done using it.

In your case aLocalFn() continues to execute simultaneously with the new thread and may even finish execution before the thread, that leaves you with an dangling pointer(pointer pointing to data that may not exist) in thread function since the local variable aLocalVar in the function ceases to exist after function returns.

Alok Save
  • 202,538
  • 53
  • 430
  • 533