我需要使用pthread_create来调用类型的C函数
int main_original(int argc, char** argv)
Run Code Online (Sandbox Code Playgroud)
我尝试过这样的事情:
pthread_create(&t, NULL, main_original, NULL);
Run Code Online (Sandbox Code Playgroud)
编译器给我一个类型错误
从'int(*)(int,char**)'到'void*()(void)'的无效转换
那么,调用main_original以正确传递其参数的正确方法是什么?
该函数pthread_create只能调用具有以下签名的函数:
void *fn(void *)
Run Code Online (Sandbox Code Playgroud)
即使您设法将指针强制转换为具有不同签名的函数并成功传递给它pthread_create,您的程序也可能会崩溃,因为它pthread_create会尝试按照平台的函数调用约定来设置堆栈/寄存器只有一个void *参数,这将导致您的函数处于不确定状态.
解决问题的方法是使用专门设计用于调用的包装函数,pthread_create如下所示:
void *main_original_start_routine(void *arg)
{
main_original(argc, argv);
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
但是,这可能还不够,除非argc并且argv是全局变量.您可能会发现还需要以某种方式将这些值从您调用的作用域传递到此函数pthread_create.这可以通过void *arg参数来完成pthread_create,通过创建一个包含所需状态的结构,并通过一个转换的void指针传递它:
struct main_original_context {
int argc;
char **argv;
};
void *main_original_start_routine(void *arg)
{
/* Convert the void pointer back to the struct pointer it
* really is. */
struct main_original_context *ctx = arg;
main_original(ctx->argc, ctx->argv);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t t;
struct main_original_context ctx = {
argc,
argv
};
/* Pass a pointer to our context struct to the thread routine. */
pthread_create(&t, NULL, &main_original_start_routine, &ctx);
pthread_join(&t, NULL);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但请记住,在这种情况下,ctx只有main函数持续时间.如果我们创建pthread的函数pthread_join在返回之前没有连接(并且使用于为线程提供上下文的结构无效),那么这将是不安全的.因此,我们必须使用动态分配,并使线程承担释放任何动态分配的内存的责任:
struct main_original_context {
int foo;
int bar;
};
void *foobar_start_routine(void *arg)
{
struct main_original_context *ctx = arg;
foobar(ctx->foo, ctx->bar);
/* Free memory we have been given responsibility for. */
free(ctx);
return NULL;
}
void asdf(int foo, int bar)
{
pthread_t t;
struct main_original_context *ctx;
/* Allocate memory. */
ctx = malloc(sizeof *ctx);
ctx->foo = foo;
ctx->bar = bar;
/* Assume `main_original_start_routine` is now responsible for freeing
* `ctx`. */
pthread_create(&t, NULL, &foobar_start_routine, ctx);
/* Now we can safely leave this scope without `ctx` being lost. In
* the real world, `t` should still be joined somewhere, or
* explicitly created as a "detached" thread. */
}
Run Code Online (Sandbox Code Playgroud)