使用pthread_create调用类型为“int argc,char ** argv - > int”的C函数

时间:2018-06-05 15:33:10

标签: c pthreads

我需要使用pthread_create来调用类型为

的C函数
int main_original(int argc, char** argv)

我尝试过这样的事情:

pthread_create(&t, NULL, main_original, NULL);

编译器给我一个类型错误

  

从'int(*)(int,char **)'无效转换为'void *()(void )'

那么,调用main_original以正确传递其参数的正确方法是什么?

1 个答案:

答案 0 :(得分:7)

函数pthread_create只能调用具有以下签名的函数:

void *fn(void *)

即使您设法将指针强制转换为具有不同签名的函数并成功将其传递给pthread_create,您的程序也可能会崩溃,因为pthread_create将尝试设置堆栈/以一种只有一个void *参数的函数遵循平台调用约定的方式注册,这将导致你的函数处于不确定状态。

解决问题的方法是使用专门为pthread_create调用的包装函数,如下所示:

void *main_original_start_routine(void *arg)
{
    main_original(argc, argv);
    return NULL;
}

但是,这可能还不够,除非argcargv是全局变量。您可能会发现还需要以某种方式将这些值从您调用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;
}

但请注意,在这种情况下,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. */
}