Quick Links:

bal | bbl | bdl | bsl

Component bslmt_threadlocalvariable
[Package bslmt]

Provide a macro to declare a thread-local variable. More...

Outline
Purpose:
Provide a macro to declare a thread-local variable.
Classes:
BSLMT_THREAD_LOCAL_VARIABLE macro to declare a thread-local variable
See also:
Description:
This component should not be used outside of the bslmt package at this time.
This component defines a macro for declaring a static thread-local variable. Where a normal static variable is located at the same memory location for all threads within a process, a thread-local static variable has a different memory location for each thread in the process:
  BSLMT_THREAD_LOCAL_VARIABLE(BASIC_TYPE, VARIABLE_NAME, INITIAL_VALUE)
      Declare, at function or namespace scope, a thread-local 'static'
      variable having the specified 'VARIABLE_NAME' of the specified
      'BASIC_TYPE' in the current context and initialize it with the
      specified 'INITIAL_VALUE'.  The 'BASIC_TYPE' must be a valid
      typename, and that typename must represent either a fundamental or a
      pointer type.  The specified 'VARIABLE_NAME' must be a valid variable
      name in the scope in which the macro is employed.  The specified
      'INITIAL_VALUE' must evaluate to a *compile-time* *constant* *value*
      of type 'BASIC_TYPE'.  If 'VARIABLE_NAME' is not a valid variable
      name, or the type of 'INITIAL_VALUE' is not convertible to type
      'BASIC_TYPE', the instantiation will result in a *compile* *time*
      error.  The behavior is undefined unless this macro is instantiated
      within a function or at file (or namespace) scope (i.e., *not* at
      class scope), and 'INITIAL_VALUE' is a *compile-time* constant.  Note
      that the instantiation of this macro is similar to the declaration:
      'static BASIC_TYPE VARIABLE_NAME = INITIAL_VALUE;'
      except that the declared variable, 'VARIABLE_NAME', refers to a
      different memory location for each thread in the process.
Note that, BSLMT_THREAD_LOCAL_VARIABLE should not be instantiated at class scope.
Platform Notes:
Since the C++ standard does not define a thread-local storage specifier, support varies between platforms and compilers. Moreover, thread-local variables are not supported on (1) Solaris with gcc or (2) Windows due to compiler or runtime limitations. See the following table for details.
 +----------+----------------------------------------------------------------
 | Platform |  Note
 |----------+----------------------------------------------------------------
 |  AIX     |  o A bug in the AIX compiler prevents compiling translation
 |          |    units with more than 10 thread-local variables with debug
 |          |    symbols.  This has been fixed in xlC8 (internal ticket
 |          |    DRQS 13819416), but has not yet been fixed for xlC10.
 |          |
 |          |  o xlC8 does not support class scoped thread-local variables.
 |----------+----------------------------------------------------------------
 | Solaris  |  o Thread local variables are not currently supported due to a
 |  gcc     |    run-time failure (on thread-exit) for tasks using
 |          |    thread-local variables.  Note that both the Solaris native
 |          |    compiler, and gcc on Linux do support thread-local
 |          |    variables.
 +----------+----------------------------------------------------------------
 | Windows/ |  o Thread local variables cause run-time errors when used
 | MSVC     |    inside a dynamic-library (.dll) that is loaded at runtime
 |          |    using 'LoadLibrary' or 'LoadLibraryEx' on versions of
 |          |    Windows prior to Vista (e.g., XP).  The problem is noted
 |          |    here:
 |          |    http://support.microsoft.com/kb/118816
 +----------+----------------------------------------------------------------
Usage:
This section illustrates intended use of this component.
Example 1: A Service Request Processor with Thread Local Context:
In the following example we create a RequestProcessor that places context information for the current request in a thread-local variable.
First, we define a trivial structure for a request context.
  // requestprocessor.h

  struct RequestContext {

      // DATA
      int d_userId;       // BB user id
      int d_workstation;  // BB LUW
  };
Next, we create a trivial RequestProcessor that provides a static class method that returns the RequestContext for the current thread, or 0 if the current thread is not processing a request.
  class RequestProcessor {
      // This class implements an "example" request processor.

      // NOT IMPLEMENTED
      RequestProcessor(const RequestProcessor&);
      RequestProcessor& operator=(const RequestProcessor&);

      // PRIVATE CLASS METHODS
      static const RequestContext *&contextReference();
          // Return a reference to a *modifiable* thread-local pointer to the
          // non-modifiable request context for this thread.  Note that this
          // method explicitly allows the pointer (but not the
          // 'RequestContext' object) to be modified by the caller to allow
          // other methods to assign the thread-local context pointer to a
          // new address.

    public:

      // CLASS METHODS
      static const RequestContext *requestContext();
          // Return the address of the non-modifiable, request context for
          // this thread, or 0 if none has been set.

      // CREATORS
      RequestProcessor() {}
          // Create a 'RequestProcessor'.

      ~RequestProcessor() {}
          // Destroy this request processor.

      // MANIPULATORS
      void processRequest(int userId, int workstation, const char *request);
          // Process (in the caller's thread) the specified 'request' for
          // the specified 'userId' and 'workstation'.
  };

  // requestprocessor.cpp

  // PRIVATE CLASS METHODS
Now, we define the contextReference method, which defines a thread-local RequestContext pointer, context, initialized to 0, and returns a reference providing modifiable access to that pointer.
  const RequestContext *&RequestProcessor::contextReference()
  {
      BSLMT_THREAD_LOCAL_VARIABLE(const RequestContext *, context, 0);
      return context;
  }

  // CLASS METHODS
  const RequestContext *RequestProcessor::requestContext()
  {
      return contextReference();
  }

  // MANIPULATORS
Then, we define the processRequest method, which first sets the thread-local pointer containing the request context, and then processes the request.
  void RequestProcessor::processRequest(int         userId,
                                        int         workstation,
                                        const char *request)
  {
      RequestContext currentContext = {userId, workstation};

      contextReference() = &currentContext;

      // Process the request.

      contextReference() = 0;
  }
Finally, we define a separate function myFunction that uses the RequestProcessor class to access the RequestContext for the current thread.
  void myFunction()
  {
      const RequestContext *context = RequestProcessor::requestContext();

      // Perform some task that makes use of this threads 'requestContext'.
      // ...
  }