Используйте pthread_create для вызова функции C типа "int argc, char ** argv -> int" - PullRequest
0 голосов
/ 05 июня 2018

Мне нужно использовать 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 голосов
/ 05 июня 2018

Функция 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;
}

Однако это может бытьдостаточно, если 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;
}

Однако имейте в виду, чтоВ этом случае 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. */
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...