Making existing ANSI C code threadsafe and re-entrant

人走茶凉 提交于 2019-12-23 03:23:44

问题


I am working on an old legacy ANSI C system, which is littered with a lot of global variables. I am part of a team refactoring the existing codebase, to make the code re-entrant and threadsafe. I found useful material on writing thread safe and re-entrant ANSI C code here.

Based on my (admittedly non-perfect) understanding, I have come up with a proposal on how to proceed - but I have already come up with some issues that need addressing, and decided it best to come in here to find out the best way to design things before actually starting to code.

/******************************************************************/
/*                                                                */
/* CURRENT situaton:                                              */
/* Global variables scattered accross a multitude of source files */
/*                                                                */
/******************************************************************/
static struct myStruct some_struct;
static long instance_counter;
static char[MAX_STR_LEN] instance_name;
static dbConnection * db_conn;
static SharedMemoryPtr * shrmem_ptr;




/*******************************************************************/
/*                                                                 */
/* PROPOSED solution:                                              */
/* Wrap all global variables into one thread local struct and      */
/* provide getter/setter* funcs for the variables (of course, this */
/* means that I will have to modify existing code to use the       */
/* context variable and the getter/setter methods instead of       */
/* directly accessing the global variables)                        */
/*                                                                 */ 
/*******************************************************************/

/* Thread local variables stored in ONE source file */

struct myStruct some_struct;
long instance_counter;
char[MAX_STR_LEN] instance_name;
dbConnection * db_conn;
SharedMemoryPtr * shrmem_ptr;


/* Thread local variable that provides getter/setter funcs to 'globals' */

typedef struct _ctx
{
    /* Getter functions */
    variable1_type (getter_func1*)(void);
    variable2_type (getter_func2*)(void);

    /* Setter functions */
    void (setter_func1*)(variable1_type v1);
    void (setter_func2*)(variable2_type v2);
} Context;

I have three MAIN questions:

  1. Is the approach I have taken a good (i.e. the best or one of the better) one?. If not, is there a better recommended (i.e. 'best practices') way of doing what I want to do?

  2. if a thread local variable is changed in one thread, is the change reflected in other threads?. If the answer is no (which I suspect it is), then it means that it is possible for two threads to be running using different values for a variable. In almost all applications I can think of, this is unacceptable - so how do existing multithreaded applications avoid this scenario?. My basic understanding tells me that a lock will have to be acquired before a write, and when there are any threads reading, the writer thread must block. If this is not the case, then I would appreciate a clarification of the correct sequence of events. I would also appreciate some pseudocode that would show how to implement this read/write ops using my sample data structures.

  3. The getter functions pseudocode I have written in the context struct should ideally return pointers for obvious reasons (to avoid copying potentially HUGE data structures everytime one is retrieved). However, according to the IBM page I referred to earlier in my question (link provided):

A reentrant function does not hold static data over successive calls, nor does it return a pointer to static data. All data is provided by the caller of the function.

So (as I understand it), the getter functions cannot return pointers to the static data (unless I am mistaken). Could someone clariry. Also, if I should not be returning pointers from the gettter functions, is there any way/technique I can use to prevent/avoid returning copies of the data (as I said, some of the structures are quite HUGE/HEAVY).

[[Aside]]

I am developing on Ubuntu 12.04 LTS, so I am interested in POSIX compliant solutions.


回答1:


The first question you should ask for each variable is: Are they?

  • read only (initialize once)
  • synchronized read/write (All threads always need a consistent copy)
  • unsynchronized read/write (each thread needs that variable, but does not need a consistent copy or is happy with a private copy)

A profiler or a debugger will be able to tell you what type you have.

Your approach works fine if all variables are of the third type, which you have already mentioned yourself is probably not true.

For the first type (read only) it is safe to leave them as is as long as the initialisation happens before the parallel code.

For the third type just put the __thread modifier infront of it and make sure it's initialized in the parallel section.

The second type is the most difficult one. You will need to use some sort of synchronization for accessing it: essentially only one thread is allowed to access it at a time.

There are 3 main models for doing this:

  • Single lock. Each access has to acquire the lock first, use the variable, release the lock. Look at pthread_mutex_* functions for that. Also you will have to decide how many variables a single lock protects, it can be as fine grained as just one all the way to large structs or arrays.
  • Readers/writers lock - this is the better choice if you allow multiple concurrent read accesses, but only one write access at a time. There is a pthread_mutex_* variant that does that.
  • Finally atomics - these are pecial hardware instructions capable of modifying up to a machine word synchronized in one go. gcc will provide you with the atomic builtins for this.

Hope this helps a bit.



来源:https://stackoverflow.com/questions/19752282/making-existing-ansi-c-code-threadsafe-and-re-entrant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!