Coolmatt69 Coolmatt69 - 3 months ago 5
C Question

Make a variable that is initialized by a function available to a function in multithreaded environment

So here is the problem I'm trying to solve, I'm programming in C.

We have a function that can initialize a struct for you.

typedef struct {
int val1;
int val2;
} custom_t;

custom_t init_custom() {
custom_t temp;

temp.val1 = 5;
temp.val2 = 5;


return temp;
}


And you would just use it like so:

custom_t some_name = init_custom();


I have 4 functions that takes the custom_t as input and can do some work with it.

In another file I have a lot of library functions that will run in a multithreaded enviroment. These library functions will all need to do work on the same custom_t variable, no matter the thread.

The library functions won't get the custom_t variable passed to it, because the goal is that another user should be able to use the library functions without thinking of the custom_t variable.

I'm thinking that I have to make the custom_t variable global in the namespace where I define the library functions but I an error saying that global variables must be const.

I am unsure how to achieve this and I would appreciate all the help I can get. If my explanation wasn't good enough feel free to ask any questions and I will try to elaborate.

EDIT:
Fixed the variable init typo

Answer

With custom_t = init_custom(); you're trying to set a typename (i.e. custom_t).

Just call it something else:

custom_t my_global_custom = init_custom();

But, to access this from multiple threads and library functions, assuming you'll need to write to it, you'll need to wrap access to this in a mutex:

pthread_mutex_t custom_mutex = PTHREAD_MUTEX_INITIALIZER;
custom_t my_global_custom;

my_global_custom = init_custom();

// how each thread must access it
pthread_mutex_lock(&custom_mutex);
func_that_uses_my_global_custom();
pthread_mutex_unlock(&custom_mutex);

UPDATE:

My example wasn't intended to be literally an initializer but an assignment:

pthread_mutex_t custom_mutex = PTHREAD_MUTEX_INITIALIZER;
custom_t my_global_custom;
custom_t my_global_2;

custom_t
init_custom(void)
{
    custom_t temp;

    temp.val1 = 5;
    temp.val2 = 5;

    return temp;
}

void
init_custom2(custom_t *temp)
{

    temp->val1 = 5;
    temp->val2 = 5;
}

int
main(void)
{

    // either one of these should work ..
    my_global_custom = init_custom();
    init_custom2(&my_global_2);

    // start some threads ...

    return 0;
}

void *
thread_func(void *)
{

    // how each thread must access it:
    pthread_mutex_lock(&custom_mutex);
    func_that_uses_my_global_custom();
    pthread_mutex_unlock(&custom_mutex);

    return (void *) 0;
}

UPDATE #2:

But do you know any way to initialize my_global_custom outside the main function? Or is that just not possible?

Another way [under gcc at least], is to create a contructor function. Given the above functions and definitions, move the init calls into:

void __attribute__((constructor))
my_global_constructor(void)
{

    my_global_custom = init_custom();
    init_custom2(&my_global_2);
}

Nothing needs to [and nothing should] call this function. It will be called automatically before main is called because it's now a special function.

These are often used by libraries that want to do some init, but don't want to burden main with having to know to call (e.g.) init_liba(); init_libb(); ... In this case, it is called at the "right" time for the library [based upon linkage, etc.].

There is also a __attribute__((destructor)) than can be used to "destroy" things [after main returns, IIRC].

For more on this, see: How exactly does __attribute__((constructor)) work?

Personally, I now use the above attribute, but, for nostalgia, I like the older .init/.fini sections.

Comments