logoalt Hacker News

groundzeros2015yesterday at 2:56 PM3 repliesview on HN

Thread locals do solve the problem. You create a wrapper around the original function. You set a global thread local user data, you pass in a function which calls the function pointer accepting the user data with the global one.


Replies

sparkietoday at 1:51 AM

Thread locals don't fully solve the problem. They work well if you immediately call the closure, but what if you want to store the closure and call it later?

    #include <stdlib.h>
    #include <string.h>
    #include <stddef.h>

    typedef int (*comp)(const void *untyped_left, const void *untyped_right);

    thread_local int in_reverse = 0;

    __attribute__((noinline))
    int compare_impl(const void *untyped_left, const void *untyped_right, int in_reverse) {
        const int* left = untyped_left;
        const int* right = untyped_right;
        return (in_reverse) ? *right - *left : *left - *right;
    }

    comp make_sort(int direction) {
        in_reverse = direction;
        int compare(const void *untyped_left, const void *untyped_right) {
            return compare_impl(untyped_left, untyped_right, in_reverse);
        }
        return compare;
    }

    int main(int argc, char* argv[]) {

        int list[] = { 2, 11, 32, 49, 57, 20, 110, 203 };

        comp normal_sort = make_sort(0);
        comp reverse_sort = make_sort(1);

        qsort(list, (sizeof(list)/sizeof(*list)), sizeof(*list), normal_sort);
            
        return list[0];
    }
Because we create `reverse_sort` between creating `normal_sort` and calling it, we end up with a reverse sort despite clearly asking for a normal sort.
show 1 reply
srcreighyesterday at 4:45 PM

Yep. Thread locals are probably faster than the other solutions shown too.

It’s confusing to me that thread locals are “not the best idea outside small snippets” meanwhile the top solution is templating on recursion depth with a constexpr limit of 11.

show 1 reply
gpderettayesterday at 5:27 PM

reentrancy.

show 1 reply