thread.h 9.63 KB
Newer Older
1
/*
2
 * Copyright (c) 2014-2015, Siemens AG. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef EMBB_BASE_THREAD_H_
#define EMBB_BASE_THREAD_H_

#include <embb/base/internal/platform.h>
#include <embb/base/internal/thread_closures.h>
#include <embb/base/mutex.h>
#include <embb/base/core_set.h>
#include <ostream>

namespace embb {
namespace base {

/**
 * \defgroup CPP_BASE_THREAD Thread
 *
 * Threads supporting thread-to-core affinities.
 *
 * \ingroup CPP_BASE
 */

/**
 * Represents a thread of execution.
 *
 * Provides an abstraction from platform-specific threading implementations to
 * create, manage, and join threads of execution. Support for thread-to-core
 * affinities is given on thread creation by using the core set functionality.
 *
 * This class is essentially a wrapper for the underlying C implementation.
 *
 * \ingroup CPP_BASE_THREAD
 */
class Thread {
 public:
  /**
   * Unique %ID of a thread that can be compared with other IDs.
   */
  class ID {
   public:
    /**
     * Constructs an empty (invalid) thread %ID.
     */
    ID() : id_() {}

   private:
    /**
     * Constructs an %ID from an IDType instance. Is done by the thread.
     */
    explicit ID(internal::IDType id) : id_(id) {}

    /**
     * Holds the actual %ID representation.
     */
    internal::IDType id_;

    /**
     * A thread needs to set its ID on start.
     */
    friend class Thread;

    /**
     * The streaming operator needs to access the internal %ID representation.
     */
    template<class CharT, class Traits>
    friend
    std::basic_ostream<CharT, Traits>&
        operator<<(std::basic_ostream<CharT, Traits>& os, Thread::ID id);

    /**
     * Comparison operators need to access the internal ID representation.
     */
    friend bool operator==(Thread::ID lhs, Thread::ID rhs);
    friend bool operator!=(Thread::ID lhs, Thread::ID rhs);
  };

  /**
   * Returns the maximum number of threads handled by EMB<sup>2</sup>.
   *
   * See embb_thread_get_max_count() for a description of the semantics.
   *
   * \return Maximum number of threads
   *
   * \lockfree
   * \see SetThreadsMaxCount()
   */
  static unsigned int GetThreadsMaxCount();

  /**
   * Sets the maximum number of threads handled by EMB<sup>2</sup>.
   *
   * \notthreadsafe
   * \see GetThreadsMaxCount()
   */
  static void SetThreadsMaxCount(
    unsigned int max_count
    /**< [IN] Maximum number of threads */
    );

  /**
   * Returns the %ID of the current thread.
   *
   * The %ID is only valid within the calling thread.
   *
   * \return %ID of the calling thread
   *
   * \threadsafe
   */
  static ID CurrentGetID();

  /**
   * Reschedule the current thread for later execution.
   *
   * This is only a request, the realization depends on the implementation and
   * the scheduler employed by the operating system.
   *
   * \threadsafe
   */
  static void CurrentYield();

  /**
   * Creates and runs a thread with zero-argument start function.
   *
   * \note If the function is passed as a temporary object when creating a
   * thread, this might be interpreted as a function declaration ("most vexing
   * parse"). C++11 resolves this by using curly braces for initialization.
   *
   * \throws NoMemoryException if not enough memory is available
   * \throws ErrorException in case of another error
   * \memory A small constant amount of memory to store the function. This
   *         memory is freed the thread is joined.
   * \notthreadsafe
157
   * \tparam Function Function object type
158 159 160 161
   */
  template<typename Function>
  explicit Thread(
    Function function
162
    /**< [IN] Copyable function object, callable without arguments */
163 164 165 166 167 168 169 170 171 172 173 174 175 176
    );

  /**
   * Creates and runs a thread with zero-argument start function.
   *
   * \note If the function is passed as a temporary object when creating a
   * thread, this might be interpreted as a function declaration ("most vexing
   * parse"). C++11 resolves this by using curly braces for initialization.
   *
   * \throws NoMemoryException if not enough memory is available
   * \throws ErrorException in case of another error
   * \memory A small constant amount of memory to store the function. This
   *         memory is freed the thread is joined.
   * \notthreadsafe
177
   * \tparam Function Function object type
178 179 180 181 182 183
   */
  template<typename Function>
  explicit Thread(
    CoreSet& core_set,
    /**< [IN] Set of cores on which the thread shall be executed. */
    Function function
184
    /**< [IN] Copyable function object, callable without arguments */
185 186 187 188 189 190 191 192 193 194 195 196 197 198
    );

  /**
   * Creates and runs a thread with one-argument thread start function.
   *
   * \note If the function is passed as a temporary object when creating a
   * thread, this might be interpreted as a function declaration ("most vexing
   * parse"). C++11 resolves this by using curly braces for initialization.
   *
   * \throws NoMemoryException if not enough memory is available
   * \throws ErrorException in case of another error
   * \memory A small constant amount of memory to store the function. This
   *         memory is freed the thread is joined.
   * \notthreadsafe
199
   * \tparam Function Function object type
200 201 202 203 204
   * \tparam Argument Type of argument
   */
  template<typename Function, typename Arg>
  Thread(
    Function function,
205
    /**< [IN] Copyable function object, callable with one argument */
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
    Arg arg
    /**< [IN] Argument for function (must be copyable) */
    );

  /**
   * Creates and runs a thread with two-argument thread start function.
   *
   * \note If the function is passed as a temporary object when creating a
   * thread, this might be interpreted as a function declaration ("most vexing
   * parse"). C++11 resolves this by using curly braces for initialization.
   *
   * \throws NoMemoryException if not enough memory is available
   * \throws ErrorException in case of another error
   * \memory A small constant amount of memory to store the function. This
   *         memory is freed the thread is joined.
   * \notthreadsafe
222
   * \tparam Function Function object type
223 224 225 226 227 228
   * \tparam Arg1 Type of first argument
   * \tparam Arg2 Type of second argument
   */
  template<typename Function, typename Arg1, typename Arg2>
  Thread(
    Function function,
229
    /**< [IN] Copyable function object, callable with two arguments */
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    Arg1 arg1,
    /**< [IN] First argument for function (must be copyable) */
    Arg2 arg2
    /**< [IN] Second argument for function (must be copyable) */
    );

  /**
   * Waits until the thread has finished execution.
   *
   * \pre The thread has been created but not yet been joined.
   * \post The thread has finished execution and dynamic memory allocated during
   *       creation has been freed.
   * \notthreadsafe
   */
  void Join();

  /**
   * Returns the thread %ID.
   *
   * \return %ID of the thread
   *
   * \threadsafe
   */
  ID GetID();

 private:
  /**
   * Performs error checks and frees resources from thread constructor.
   *
   * \tparam ThreadClosure Type of thread closure
   */
  template<typename ThreadClosure>
  void CheckThreadCreationErrors(
    int result,
    /**< [IN] Result value of creating thread with C API */
    ThreadClosure* closure
    /**< [IN] Closure used when creating thread */
    );

  /**
   * Disables copying and assignment.
   */
  Thread(const Thread&);
  Thread& operator=(const Thread&);

  /**
   * Holds native implementation thread handle.
   */
  internal::ThreadType rep_;
};

/**
 * Compares two thread IDs for equality.
 *
 * \return \c true if thread IDs are equivalent, otherwise \c false
 *
 * \ingroup CPP_BASE_THREAD
 */
bool operator==(
  Thread::ID lhs,
  /**< [IN] Left-hand side of equality sign */
  Thread::ID rhs
  /**< [IN] Right-hand side of equality sign */
  );

/**
 * Compares two thread IDs for inequality.
 *
 * \return \c true if thread IDs are not equivalent, otherwise \c false
 *
 * \ingroup CPP_BASE_THREAD
 */
bool operator!=(
    Thread::ID lhs,
    /**< [IN] Left-hand side of inequality sign */
    Thread::ID rhs
    /**< [IN] Left-hand side of inequality sign */
    );

/**
 * Writes thread %ID to stream.
 *
 * \return Reference to the stream
 *
 * \ingroup CPP_BASE_THREAD
 */
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
    operator<<(
      std::basic_ostream<CharT, Traits>& os,
      /**< [IN/OUT] Stream to which thread %ID is written */
      Thread::ID id
      /**< [IN] %Thread %ID to be written */
      );

} // namespace base
} // namespace embb

#include <embb/base/internal/thread-inl.h>

#endif // EMBB_BASE_THREAD_H_