RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Thanks for Not Sharing, Or, How to Define Thread-Local Data-2 : Page 2

Presenting the Problem
Suppose you're designing server application that serves incoming requests from a client. The client must login before issuing a request from the server. However, if the client has already logged in successfully, you certainly don't want to force it to repeat the slow login process. To keep track of the client's status, the thread function uses a local static flag that is set to true after the first successful login of the client. If that flag is false, the thread function will call a login function in a loop up to MAX_TRY times before processing the client's request. If the login attempts have failed, the thread function returns a negative value:

int client_req()
  static bool connected=false;
  for (int n=0; n<MAX_TRY; n++)
   if(connected)//skip login, get request code right away
    return get_code();
   else //attempt to login up to MAX_TRY times
    connected=(login()==OK? true : false);
  return -1; //we get here only after MAX_TRY failures
Using local static variables inside a function is a common technique used to recall a previously stored state or session. However, there is one problem with this approach: the variable connected is shared among all threads calling client_req(). Therefore, a race-condition will occur if one thread is reading connected while another thread is modifying it. Until not long ago, the common solution to this problem was to synchronize access to the shared data, e.g., by using critical sections or mutexes. However, a closer examination of the code reveals that there's no call for synchronized access at all. Rather, what you really need is for each thread to receive its own private copy of connected. How do you do that?

Objects with auto and register storage types are not a problem—they are thread unique anyway because each thread has its own stack. By contrast, static storage objects reside in a memory section that is accessible to all threads of the same process. Objects with static storage duration include:

  • Global objects, and more generally, objects declared in a namespace scope
  • File-scope static objects
  • Local static objects declared inside a function or a block
  • Static data members of a class
Any of these can now become thread-local. The C++0x thread_local keyword designates a thread-local object. The resolution and scope of a variable declared with the thread_local storage type are as they would be without the thread_local keyword. For example:

extern thread_local int global_i; //global
int client_req()
 thread_local static bool connected=false; //local static
thread_local static void *p=0; //file static
Using thread_local for variables that do not have static storage type is an error:

int func(thread_local int x);//error, arguments are auto
Notice that static and thread_local aren't mutually exclusive. In the declarations of p above, static indicates internal linkage (i.e., the variable isn't visible from other translation units), whereas thread_local indicates that every thread gets a private copy of p.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date