传递本地变量给线程。这是可能的吗?

7
我正在使用gcc工作,我想知道以下是否可行:
我有一个函数(不是main而是aLocalFn),并在其中声明了一个局部变量。然后,我将此局部参数作为线程参数传递。这可行吗?还是有可能(取决于首先运行什么)在运行threadFunction之前会丢失aLocalVar,并且引用idxPtr指向无意义的值?
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;
}   

感谢您的帮助。

5个回答

8

这段代码是错误的。函数aLocalFn有可能在线程函数开始执行前就返回了。因此,当线程函数读取本地变量时,该变量所在的作用域可能已经结束。

可能会让人感到困惑的是,这段代码有时候可能表现得很正常。然而,它是错误的,您应该使用堆分配的内存。


只是想确认一下:如果我将代码更改为 pthread_create(&thread_id,NULL,threadFunction, &aLocalVar),并在 pthread_create 之后的某个地方使用 pthread_join,这样做是否可以? - Rick

4

这是可行的,但你的问题中没有涉及相关的代码。你需要添加一个信号变量来指示新线程何时完成。在使用该变量后,外部函数便可返回。

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;
}   

请注意,此示例代码本身不是线程安全的(如果多个线程调用aLocalFn)。
这使代码变得复杂,并且锁定操作很昂贵。因此,在大多数情况下,您最好将数据存储在堆中,让新线程或pthread_join代码自由释放它。

2
是的,这确实可以完成任务,但这绝不是一个好的解决方案。我相信你不会推荐这个,比如堆分配。 - David Heffernan
我尽量不做超出问题陈述的假设。在aLocalFn是一个回调函数且数据在返回时会自动释放的情况下,我曾经需要类似的代码。对于一个简单的int来说,这并不是一个很好的解决方案。 - Per Johansson
+1 for a 'different' answer. 但是,我也不同意这是一个好的解决方案,因为它需要创建不必要的条件变量并使创建线程等待已创建线程完成,从而占用了创建者线程的资源。 - Jay
如果您知道代码只会生成一个threadFunction实例,那么这可能是一个可接受的解决方案。 - nass

4

您的代码存在“aLocalVar”的生命周期问题,如果您只想传递一个整数,这里有一种不可移植的方法可以实现。但是它在某些平台上无法工作,但您不太可能遇到这些问题。

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

int rec_idx = returnsRecordIndex();
pthread_create (&thread1, &attr_detached, (void *) &threadFunction, (void *)rec_idx);

2

@pizza的回答是我会采取的方式。另外一种方法是使用malloc/free,正如@David所提示的那样。我肯定会选择这种方法,而不是在其他答案中提出的等待循环。

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;
}   

1
无论何时,当您将变量传递给线程函数时,您的工作就是确保该变量在线程函数使用它完成之前保持活动和有效。在您的情况下,aLocalFn() 与新线程同时执行,甚至可能在线程之前完成执行,这会在线程函数中留下一个悬空指针(指向可能不存在的数据),因为函数中的局部变量aLocalVar在函数返回后就不存在了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接