Quick Links:

bal | bbl | bdl | bsl

Namespaces | Typedefs

Component bslmt_threadutil
[Package bslmt]

Provide platform-independent utilities related to threading. More...

Namespaces

namespace  bslmt

Typedefs

typedef void *(* bslmt_ThreadFunction )(void *)
typedef void(* bslmt_KeyDestructorFunction )(void *)

Detailed Description

Outline
Purpose:
Provide platform-independent utilities related to threading.
Classes:
bslmt::ThreadUtil namespace for portable thread management utilities
See also:
Component bslmt_threadattributes, Component bslmt_configuration
Description:
This component defines a utility struct, bslmt::ThreadUtil, that serves as a name space for a suite of pure functions to create threads, join them (make one thread block and wait for another thread to exit), manipulate thread handles, manipulate the current thread, and (on some platforms) access thread-local storage.
Creating a Simple Thread with Default Attributes:
Clients call bslmt::ThreadUtil::create() to create threads. Threads may be started using a "C" linkage function pointer (of a type defined by bslmt::ThreadUtil::ThreadFunction) and a void pointer to userData to be passed to the function; or an "invokable" object of parameterized type (any copy-constructible type on which operator() may be invoked). The invoked function becomes the main driver for the new thread; when it returns, the thread terminates.
Thread Identity:
A thread is identified by an object of the opaque type bslmt::ThreadUtil::Handle. A handle of this type is returned when a thread is created (using bslmt::ThreadUtil::create). A client can also retrieve a Handle for the "current" thread via the self method: Several thread manipulation functions in bslmt::ThreadUtil take a thread handle, or pointer to a thread handle, as an argument. To facilitate compatibility with existing systems and allow for non-portable operations, clients also have access to the bslmt::ThreadUtil::NativeHandle type, which exposes the underlying, platform-specific thread identifier type: Note that the returned native handle may not be a globally unique identifier for the thread, and, e.g., should not be converted to an integer identifier, or used as a key in a map.
Setting Thread Priorities:
bslmt::ThreadUtil allows clients to configure the priority of newly created threads by setting the inheritSchedule, schedulingPolicy, and schedulingPriority of a thread attributes object supplied to the create method. The range of legal values for schedulingPriority depends on both the platform and the value of schedulingPolicy, and can be obtained from the getMinSchedulingPriority and getMaxSchedulingPriority methods. Both schedulingPolicy and schedulingPriority are ignored unless inheritSchedule is false (the default value is true). Note that not only is effective setting of thread priorities workable on only some combinations of platforms and user privileges, but setting the thread policy and priority appropriately for one platform may cause thread creation to fail on another platform. Also note that an unset thread priority may be interpreted as being outside the valid range defined by [ getMinSchedulingPriority(policy), getMaxSchedulingPriority(policy) ].
 Platform      Restrictions
 ------------  --------------------------------------------------------------
 Solaris 5.10  None.

 Solaris 5.11  Spawning of threads fails if 'schedulingPolicy' is
               'BSLMT_SCHED_FIFO' or 'BSLMT_SCHED_RR'.  Thread priorities
               should not be used on Solaris 5.11 as it is not clear that
               they have any detectable effect.  Note that
               'getMinSchedulingPriority' and 'getMaxSchedulingPriority'
               return different values than on Solaris 5.10.

 AIX           For non-privileged clients, spawning of threads fails if
               'schedulingPolicy' is 'BSLMT_SCHED_FIFO' or 'BSLMT_SCHED_RR'.

 Linux         Non-privileged clients *can* *not* make effective use of
               thread priorities -- spawning of threads fails if
               'schedulingPolicy' is 'BSLMT_SCHED_FIFO' or 'BSLMT_SCHED_RR',
               and 'getMinSchedulingPriority == getMaxSchedulingPriority' if
               the policy has any other value.

 Darwin        Non-privileged clients *can* *not* make effective use of
               thread priorities -- there is no observable difference in
               urgency between high priority and low priority threads.
               Spawning of threads does succeed, however, for all scheduling
               policies.

 Windows       Clients *can* *not* make effective use of thread priorities --
               'schedulingPolicy', 'schedulingPriority', and
               'inheritSchedule' are ignored for all clients.
Supported Clock-Types:
bsls::SystemClockType supplies the enumeration indicating the system clock on which timeouts supplied to other methods should be based. If the clock type indicated at construction is bsls::SystemClockType::e_REALTIME, the absTime argument passed to the timedWait method of the various synchronization primitives offered in bslmt should be expressed as an absolute offset since 00:00:00 UTC, January 1, 1970 (which matches the epoch used in bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME). If the clock type indicated at construction is bsls::SystemClockType::e_MONOTONIC, the absTime argument passed to the timedWait method of the various synchronization primitives offered in bslmt should be expressed as an absolute offset since the epoch of this clock (which matches the epoch used in bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC).
Usage:
This section illustrates the intended use of this component.
Example 1: Creating a Simple Thread with Default Attributes:
In this example, we create a thread using the default attribute settings. Upon creation, the thread executes the user-supplied C-linkage function myThreadFunction that counts 5 seconds before terminating:
First, we create a function that will run in the spawned thread:
  extern "C" void *myThreadFunction(void *)
      // Print to standard output "Another second has passed" every second
      // for five seconds, and return 0.
  {
      for (int i = 0; i < 3; ++i) {
          bslmt::ThreadUtil::microSleep(0, 1);
          bsl::cout << "Another second has passed." << bsl::endl;
      }
      return 0;
  }
Now, we show how to create and join the thread.
After creating the thread, the main routine joins the thread, which, in effect, causes main to wait for execution of myThreadFunction to complete, and guarantees that the output from main will follow the last output from the user-supplied function:
  int main()
  {
      bslmt::Configuration::setDefaultThreadStackSize(
                  bslmt::Configuration::recommendedDefaultThreadStackSize());

      bslmt::ThreadUtil::Handle handle;

      bslmt::ThreadAttributes attr;
      attr.setStackSize(1024 * 1024);

      int rc = bslmt::ThreadUtil::create(&handle, attr, myThreadFunction, 0);
      assert(0 == rc);

      bslmt::ThreadUtil::yield();

      rc = bslmt::ThreadUtil::join(handle);
      assert(0 == rc);

      bsl::cout << "A three second interval has elapsed\n";

      return 0;
  }
Finally, the output of this program is:
  Another second has passed.
  Another second has passed.
  Another second has passed.
  A three second interval has elapsed.
Example 2: Creating a Simple Thread with User-Specified Attributes:
In this example, we will choose to override the default thread attribute values.
The attributes of a thread can be specified explicitly by supplying a bslmt::ThreadAttributes object to the create method. For instance, we could specify a smaller stack size for a thread to conserve system resources if we know that we will require not require the platform's default stack size.
First, we define our thread function, noting that it doesn't need much stack space:
  extern "C" void *mySmallStackThreadFunction(void *threadArg)
      // Initialize a small object on the stack and do some work.
  {
      char *initValue = (char *)threadArg;
      char Small[8];
      bsl::memset(&Small[0], *initValue, 8);
      // do some work ...
      return 0;
  }
Finally, we show how to create a detached thread running the function just created with a small stack size:
  void createSmallStackSizeThread()
      // Create a detached thread with a small stack size and perform some
      // work.
  {
      enum { k_STACK_SIZE = 16384 };
      bslmt::ThreadAttributes attributes;
      attributes.setDetachedState(
                             bslmt::ThreadAttributes::e_CREATE_DETACHED);
      attributes.setStackSize(k_STACK_SIZE);

      char initValue = 1;
      bslmt::ThreadUtil::Handle handle;
      int status = bslmt::ThreadUtil::create(&handle,
                                            attributes,
                                            mySmallStackThreadFunction,
                                            &initValue);
  }
Example 3: Setting Thread Priorities:
In this example we demonstrate creating 3 threads with different priorities. We use the convertToSchedulingPriority function to translate a normalized, floating-point priority in the range [ 0.0, 1.0 ] to an integer priority in the range [ getMinSchedulingPriority, getMaxSchedulingPriority ] to set the schedulingPriority attribute.
  void runSeveralThreads()
      // Create 3 threads with different priorities and then wait for them
      // all to finish.
  {
      enum { k_NUM_THREADS = 3 };

      bslmt::ThreadUtil::Handle handles[k_NUM_THREADS];
      bslmt_ThreadFunction functions[k_NUM_THREADS] = {
                                                MostUrgentThreadFunctor,
                                                FairlyUrgentThreadFunctor,
                                                LeastUrgentThreadFunctor };
      double priorities[k_NUM_THREADS] = { 1.0, 0.5, 0.0 };

      bslmt::ThreadAttributes attributes;
      attributes.setInheritSchedule(false);
      const bslmt::ThreadAttributes::SchedulingPolicy policy =
                                  bslmt::ThreadAttributes::e_SCHED_OTHER;
      attributes.setSchedulingPolicy(policy);

      for (int i = 0; i < k_NUM_THREADS; ++i) {
          attributes.setSchedulingPriority(
               bslmt::ThreadUtil::convertToSchedulingPriority(policy,
                                                             priorities[i]));
          int rc = bslmt::ThreadUtil::create(&handles[i],
                                             attributes,
                                             functions[i], 0);
          assert(0 == rc);
      }

      for (int i = 0; i < k_NUM_THREADS; ++i) {
          int rc = bslmt::ThreadUtil::join(handles[i]);
          assert(0 == rc);
      }
  }

Typedef Documentation

typedef void*(* bslmt_ThreadFunction)(void *)

bslmt_ThreadFunction is an alias for a function type taking a single void pointer argument and returning void *. Such functions are suitable to be specified as thread entry-point functions to bslmt::ThreadUtil::create. Note that create also accepts any invokable C++ "functor" object.

typedef void(* bslmt_KeyDestructorFunction)(void *)

bslmt_KeyDestructorFunction is an alias for a function type taking a single void pointer argument and returning void. Such functions are suitable to be specified as thread-specific key destructor functions to bslmt::ThreadUtil::createKey.