L0rDvAd3r_9
L0rDvAd3r_9

Reputation: 33

Passing Unsigned Long Long to pthread_create by reference

If I wanted to pass an unsigned long long to a pthread_create function call, how would I do this? I understand that due to pthread_create having void * as the last argument means that there are opportunities for type safety issues to arise.

I've seen it done like this with integers:

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

And then the int is dereferenced within the function that the thread executes. Would the same work if "i" was an unsigned long long type? Basically what I want to do is get the thread id of the thread in an unsigned long long variable using gettid(). Thank you for your help!

Upvotes: 0

Views: 572

Answers (1)

tennessee
tennessee

Reputation: 26

Sometimes, generalizing the problem helps to see the solution. Casting an int to a void * is an old trick to try and avoid memory allocation. Sometimes you just want to configure the thread that will run with more than just an int.

A common approach I use to configure pthreads is to calloc some structure, or even the space for a single value (e.g. an unsigned long long), pass it to the pthread arg and consume it in my thread function before the while (1) of the main thread logic, then free.

This allows you to pass as much or little as you want, is always OK no matter the size of what you pass in, and doesn't try to shove values in pointers.

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);
// ...

For your particular example of an unsigned long long, you could have just allocated it instead of a struct:

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

Then passed it:

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

The free() would be done in same place, and you can cast from void * to unsigned long long * in your thread runner.

See https://gist.github.com/tcarmelveilleux/967728df33215d66e2e126637270901c for a full single-file-compilable example.

Upvotes: 0

Related Questions