cmultithreadingshared-resource

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


Solution

  • 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.