Передача Unsigned Long Long в pthread_create по ссылке

Если бы я хотел передать unsigned long long вызову функции pthread_create, как бы я это сделал? Я понимаю, что из-за того, что pthread_create имеет void * в качестве последнего аргумента, это означает, что могут возникнуть проблемы с безопасностью типов.

Я видел, как это делается с целыми числами:

int i = 0;
pthread_create(..., ..., ..., (void *)&i);

И затем int разыменовывается внутри функции, которую выполняет поток. Будет ли работать то же самое, если «i» будет типом unsigned long long? В основном то, что я хочу сделать, это получить идентификатор потока потока в длинной длинной переменной без знака, используя gettid(). Спасибо за помощь!


person L0rDvAd3r_9    schedule 04.05.2018    source источник
comment
да. вы можете передать указатель на что угодно, пока процедура запуска, которую вы также передали, как на той же длине волны, и отбрасывает ее обратно.   -  person bruceg    schedule 04.05.2018
comment
Неважно, какой это тип. Указатель на переменную — это указатель на переменную. Другое дело, что происходит с переменной после вызова pthread_create... Если это, например, переменная-итератор цикла for, которую вы меняете в цикле, то значение будет меняться во всех потоках, на которые вы передали указатель. Здесь есть хитрость, которая может передавать значения через умное приведение: (void *)(uintptr_t) i. Тогда сделайте наоборот в треде: int i = (int)(uintptr_t) pi;   -  person Some programmer dude    schedule 04.05.2018
comment
Спасибо за помощь!   -  person L0rDvAd3r_9    schedule 04.05.2018
comment
gettid() возвращает pid_t, а не unsigned long long.   -  person alk    schedule 05.05.2018
comment
Да, но unsigned long long должен гарантированно хранить его.   -  person L0rDvAd3r_9    schedule 05.05.2018
comment
Кроме того, я забыл упомянуть, что переносимость не является большой проблемой. Я специально ориентируюсь на системы Linux.   -  person L0rDvAd3r_9    schedule 05.05.2018


Ответы (1)


Иногда обобщение проблемы помогает увидеть решение. Преобразование int в void * — это старый прием, позволяющий избежать выделения памяти. Иногда вы просто хотите настроить поток, который будет работать с чем-то большим, чем просто int.

Обычный подход, который я использую для настройки pthreads, состоит в том, чтобы calloc некоторую структуру или даже пространство для одного значения (например, unsigned long long), передать его аргументу pthread и использовать его в моей функции потока до while (1) основной логики потока, затем free.

Это позволяет вам передавать столько или меньше, сколько вы хотите, всегда в порядке, независимо от размера того, что вы передаете, и не пытается засунуть значения в указатели.

typedef struct {
    unsigned long long large_serial_number;
    const char *my_name;
    pthread_t caller_thread;
} fun_thread_args_t;

static void* _fun_thread_run(void *arg) {
    // Get our thread args from the dynamically allocated thread args passed-in
    fun_thread_args_t *thread_args = (fun_thread_args_t *)arg;

    bool done = false;
    while (!done) {
        // Use args here in your thread loop
        ...
    }

    // Free incoming args pointer before exiting the thread loop.
    free(arg);
    return NULL;
}

static pthread_t *_launch_fun_thread(pthread_t *thread, unsigned long long serial_number, const char *name) {
    // TODO: Of course, error-handle all the return values properly ;)

    // Allocate and prepare args for the thread
    fun_thread_args_t *args = calloc(1, sizeof(args));

    args->caller_thread = pthread_self();
    args->large_serial_number = serial_number;
    args->my_name = name;

    //  Create the thread, passing the args pointer from heap
    int rc = pthread_create(thread, NULL, &_fun_thread_run, args);
    if (0 == rc) {
        // We return here, all is well, no stack data leak, args in heap
        return thread;
    } else {
        free(args);
        return NULL;
    }
}

// ...

// Elsewhere, start some threads!
pthread_t fun_thread1;
pthread_t fun_thread2;

_launch_fun_thread(&fun_thread1, 0xABCDEF12345678ULL, "super FUN thread 1");
usleep(500UL * 1000UL);
_launch_fun_thread(&fun_thread2, 0xDEADBEEF55AA55ULL, "super FUN thread 2");

pthread_join(fun_thread1, NULL);
pthread_join(fun_thread2, NULL);
// ...

Для вашего конкретного примера unsigned long long вы могли бы просто выделить его вместо структуры:

unsigned long long *thread_arg = calloc(1, sizeof(*thread_arg));
*thread_arg = 123456;

Затем передал:

pthread_create(thread, NULL, &_fun_thread_run, (void *)thread_arg);

free() будет выполнено в том же месте, и вы можете преобразовать от void * до unsigned long long * в бегунке потоков.

См. https://gist.github.com/tcarmelveilleux/967728df33215d66e2e126637270901c. - компилируемый пример.

person tennessee    schedule 08.05.2018