views:

311

answers:

4

I have global static variables in a C library, which generate exceptions in a multithread run. I need to make them safe in some way (i.e., each thread should relate to a different instance of these variables). Any recommended methods?

+1  A: 

Most compilers have some way of designating thread-local storage. Assuming it's available, that's what you want.

Jerry Coffin
+5  A: 

There is no standard way that works across all C implementations, but implementation-specific solutions exist. For example, with Microsoft's compiler (see the docs),

__declspec( thread ) int tls_i = 1;

makes tls_i live in thread-local storage (each thread has its own separate instance of this variable). With gcc, the syntax is

__thread int tls_i;

You may also want to check the wikipedia entry on the subject.

Alex Martelli
Anything specific for gcc?
giladsah
@giladsah: Read the second half of the answer!
Donal Fellows
@giladsah, sure, the `__thread` keyword as I just said in my answer (I also pointed to a `gcc` doc page about thread-local storage for more details).
Alex Martelli
Ok, I tried using __thread and it works fine. thanks.
giladsah
+4  A: 

First question:

  • do the threads need their own copies of the variables?
  • or do they need to coordinate access to a single shared copy?

If you need the former, the other answers have made suggestions about 'thread-local storage'.

If you need the latter, then somehow or another you need to ensure there's an appropriate mutex on those variables (the scope of the mutex is one of the issues you face), and that the threads all use the mutex, and release the mutex. This is trickier. It may even be that you need to provide functions that control access to the variables.

The standard variable errno can be a modifiable lvalue:

extern int *_errno_func(void);
#define errno (*(_errno_func)())

In a threaded application (compiled with -DREENTRANT), this is what happens; on MacOS X, it appears to be what happens anyway (they use the name __error instead of _errno_func; both are in the implementation's namespace).

You may want to, or end up having to, do something similar for your variables. The fact that you say they are static improves things a bit. You only have one file to deal with (unless you are careless enough to pass back - or on - pointers to those variables).

Jonathan Leffler
+2  A: 

What you needed is TLS(Thread Local Storage), which is also known as thread-specific data or thread-private data. This mechanism can guarantee each thread to access its own separate copy of data, without worrying about synchronizing access with other threads.


There are two methods to use TLS:

  1. implicit: using keyword

    Windows: __declspec(thread) int tls_var = 10;

    Linux with GCC: __thread int tls_var = 10

  2. explicit: using specific TLS related API

    Windows:

      TlsAlloc(): allocate memory for tls data
      TlsFree(): free the memory of tls data
      TlsSetValue(): set tls' value
      TlsGetValue(): get tls' value

    Please refer to MSDN for detailed information.

    LInux with GCC:

      pthread_key_create(): create the tls data
      pthread_key_delete(): destory the tls data
      pthread_getspecific(): get tls' value
      pthread_setspecific(): set tls' value
    Turn to manpage for specific and detailed information.

Emacs