C:如何安全正确地将多个参数传递给pthread?
考虑这个简单的代码:
void* threadFunction(void* arg) { int argument=(int)arg; printf("%d recieved\n", argument); return NULL; } int main(int argv, char* argc[]) { int error; int i=0; pthread_t thread; int argument_to_thread=0; if ((error=pthread_create(&thread, NULL, threadFunction, (void*)argument_to_thread))!=0) { printf("Can't create thread: [%s]\n", strerror(error)); return 1; } pthread_join(thread, NULL); return 0; }
这有效,但这里有两件事让我烦恼。
首先,我想向threadFunction()发送多个参数。
当然,我可以传递指向数组的指针,但是如果我想传递两个不同类型的参数呢? (说一个int
和char*
)怎么做?
在这里困扰我的第二件事是我在编译上面时得到的警告……
test2.c: In function 'threadFunction': test2.c:8:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] int argument=(int)arg; ^ test2.c: In function 'main': test2.c:24:59: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] if ((error=pthread_create(&thread, NULL, threadFunction, (void*)argument_to_thread))!=0) { ^
现在,我可以通过这样做来消除这种情况:
if ((error=pthread_create(&thread, NULL, threadFunction, (void*)&argument_to_thread))!=0) { printf("Can't create thread: [%s]\n", strerror(error)); return 1; }
但是,让我说我不想通过引用传递它…有没有方法传递,说…一个int,值作为参数而没有编译器警告我?
有两种方法可以做到这一点:
-
使用
malloc
获取参数结构的存储空间,并让新线程负责在参数完成后free
调用。 (注意:如果pthread_create
失败,则需要在故障路径中free
此存储空间。) -
使用信号量(或其他同步,但信号量是目前最轻的)。
以下是后者的一个例子:
struct args { int a; char *b; sem_t sem; }; void *thread_func(void *p) { struct args *args = p; int a = args->a; char *b = args->b; sem_post(args->sem); ... } /* in caller */ struct args args; args.a = ...; args.b = ...; sem_init(&args.sem, 0, 0); pthread_create(&tid, 0, thread_func, &args); sem_wait(&args.sem); ...
如果你想通过值传递,但让警告消失,请使用此强制转换:
(void *)(uintptr_t)argument_to_thread
通过uintptr_t
的中间uintptr_t
避免了大小不匹配。 同样,在回退时,使用:
(int)(uintptr_t)voidptr_arg
如评论中所述,不一定建议采用上述方法,因为它依赖于实现定义的行为。 一个完全可移植的方法,假设您不需要全范围的int
但只需要很小的范围,是:
static const char int_to_ptr_trick[MAXVAL]; void *ptr = int_to_ptr_trick + int_val; int int_val = (char *)ptr - int_to_ptr_trick;
传递整数的地址。
int argument = 123 ; pthread_create(&thread, NULL, threadFunction, &argument)) ;
并在线程函数中
int argument= *(int*)arg ;
如果您希望传递多个参数,则可以使用与上述示例相同的方法创建包含值的结构。
如果函数的参数为void *,则不能按值传递整数。 您必须提供变量或结构的地址。