GIT repositories

Index page of all the GIT repositories that are clonable form this server via HTTPS. Übersichtsseite aller GIT-Repositories, die von diesem Server aus über git clone (HTTPS) erreichbar sind.

Services

A bunch of service scripts to convert, analyse and generate data. Ein paar Services zum Konvertieren, Analysieren und Generieren von Daten.

GNU octave web interface

A web interface for GNU Octave, which allows to run scientific calculations from netbooks, tables or smartphones. The interface provides a web form generator for Octave script parameters with pre-validation, automatic script list generation, as well presenting of output text, figures and files in a output HTML page. Ein Webinterface für GNU-Octave, mit dem wissenschaftliche Berechnungen von Netbooks, Tablets oder Smartphones aus durchgeführt werden können. Die Schnittstelle beinhaltet einen Formulargenerator für Octave-Scriptparameter, mit Einheiten und Einfabevalidierung. Textausgabe, Abbildungen und generierte Dateien werden abgefangen und in einer HTML-Seite dem Nutzer als Ergebnis zur Verfügung gestellt.

C++ Klassen-Templates für Threads/Synchronisation

C++ Thread / synchronisation class templates

Threading Support-Klassen:

  • Anmerkung: Ab C++11 sollte die STL verwendet werden: #include <thread> / <mutex> / <future>, usw.

  • Anmerkung: LINUX: mit Bibliothek -lpthread linken.

  • class sw::sync::lock Ein einfaches "Lock" zum absperren und freigeben einer Resource im Prozess, für Windows mit ***CriticalSection, unter *nix mit pthread_mutex*** realisiert. Methoden: (lock(), unlock(), trylock(), lock2(), unlock2()). Die Methoden sind inline, Instanzvariablen mutable.

  • class sw::sync::autolock / class sw::templates::basic_autolock<lock_type> : Automaisches "locking" bei Erstellen des Objekts, "unlocking" im Destruktor. Mit der Methode locked() kann geprüft werden, ob das Absperren funktioniert hat, zusätzlich kann mit lock() und unlock() explizit abgesperrt oder freigegeben werden. Auch hier: Methoden inline, Variablen mutable.

  • class sw::sync::synchronised<data type> ist ein Template für Variablen mit eingebauter Synchronisation (lock).

  • class sw::sync::fifo<element_type, container_type=std::deque>: Einfacher, auf STL Containern basierter FiFo. Methoden: empty(), size(), first(), last(), sowie put(..) und get() zum hinein-/hinausschieben von Daten.

  • class sw::thread / class sw::templates::basic_thread<..>: Einfacher vererbungsbasierter Thread-Wrapper. Statt einer Threadfunktion stehen drei virtuelle "Callback"-Methoden zur Verfügung, die überladen werden können: on_start(), on_loop(), und on_stop(), Hinzu kommen die Methoden start(), stop(), running() und stopped(). Statische Hilfsfunktionen dienen der Ermittelung von Thread-Ids, homogenisertem usleep, etc.

Threading support class templates:

  • Note: std >= C++11: Use STL: #include <thread> / <mutex> / <future>, usw.

  • Note: LINUX: link with library -lpthread.

  • class sw::sync::lock: Supports thread lock/unlock with boolean success return, no exceptions. (lock(), unlock(), trylock(), lock2(), unlock2()). Methods are inline, instance variables mutable to enable use in const context.

  • class sw::sync::autolock: Supports automatic locking for "save return" use in methods and functions. The constructor locks, the destructor unlocks. Supports method locked() to check if the resource could be locked, and lock(), unlock() for explicit locking/unlocking. Methods are inline, variables mutable.

  • class sw::sync::synchronised<data type>: Simple interlocked primitive wrapper with operators.

  • class sw::sync::fifo<element_type, container_type=std::deque>: Simple interlocked FiFi based on STL compatible containers. Provides mainly methods empty(), size(), first(), last() to inspect, and put(..), get() to append or shift out elements.

  • class sw::thread: Simple inheritance based thread wrapper. Overload the methods on_start(), on_loop(), and on_stop() to add the functionality you need. External control and checks can be done with the methods start() and stop(), running(), stopped(). Static auxiliary methods encompass getting the id of the current thread, sleeping, etc.

Dateien

Files

thread.hh example

Beispiele

Examples

#define SW_CTRACE
#include <thread.hh>
#include "test.hh"
 
using namespace std;
using namespace sw;
 
////////////////////////////////////////////////////////////////////////////////////////////////////
// only static const check
static void test_lock()
{
  sync::lock m;
  test_expect( m.lock() );
  // Must always succeed as the lock mutex/critical section is recursive,
  // and there is no other thread in this example to block it.
  test_expect( m.trylock() );
  test_expect( m.unlock() );
  test_expect( m.trylock() );
  test_expect( m.trylock() );
  test_expect( m.unlock() );
  test_expect( m.unlock() );
  test_expect( m.unlock() );
}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
// autolock
sw::sync::lock lck;
int locked_int = 0;
 
static int get_locked_int()
{
  sw::sync::autolock al(lck);  // Locks in the constructor
  if(!al.locked()) { }          // Error handling
  return locked_int;            // locked until end of function
}
 
static void set_locked_int(int i)
{
  sw::sync::autolock al(lck);
  if(!al.locked()) { ; }  // Error handling
  locked_int = i;         // locked until end of function
  al.unlock();            // Unlocking earlier is possible ..
  al.lock();              // and re-locking
}
 
static void test_autolock()
{
  test_expect(get_locked_int() == 0);
  test_expect_noexcept( set_locked_int(1) );
  test_expect(get_locked_int() == 1);
}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
// only static const check
static void test_synchronized()
{
  sw::sync::synchronized<int> locked_int(0);
  test_expect_noexcept(locked_int = 0);   // Locks, assigns, unlocks
  test_expect( locked_int == 0);          // Locks, reads, unlocks
  test_expect_noexcept( locked_int = 1 ); // Locks, assigns, unlocks
  test_expect( locked_int == 1);          // Locks, reads, unlocks
}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
// only static const check
static void test_fifo()
{
  typedef sw::sync::fifo<int> int_fifo;
  int_fifo fifo;
  test_expect(fifo.empty());
  test_expect(fifo.size() == 0);
  test_expect_noexcept( fifo.put(1) );
  test_expect_noexcept( fifo.put(2) );
  test_expect(!fifo.empty());
  test_expect(fifo.size() == 2);
  test_expect(fifo.first() == 1);
  test_expect(fifo.last() == 2);
  test_expect_noexcept( fifo.put(3) );
  test_expect_noexcept( fifo.put(4) );
  test_expect(!fifo.empty());
  test_expect(fifo.size() == 4);
  test_expect(fifo.first() == 1);
  test_expect(fifo.last() == 4);
  test_expect(fifo.get() == 1);
  test_expect(fifo.get() == 2);
  test_expect(!fifo.empty());
  test_expect(fifo.size() == 2);
  test_expect(fifo.first() == 3);
  test_expect(fifo.last() == 4);
  test_expect(fifo.get() == 3);
  test_expect(fifo.get() == 4);
  test_expect(fifo.empty());
  test_expect(fifo.size() == 0);
  test_expect_except( fifo.first() );
}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
// Thread test
sync::fifo<int> fifo;
 
class tx_thread : public thread
{
public:
 
  tx_thread() : thread(), counter(0)
  { test_comment("tx_thread::tx_thread()"); thread::start(); }
 
  explicit tx_thread(int initial) : thread(), counter(initial)
  { test_comment("tx_thread::tx_thread()"); thread::start(); }
 
  virtual ~tx_thread()
  { test_comment("tx_thread::~tx_thread()"); }
 
protected:
 
  void on_start()
  { test_comment("tx_thread::on_start()"); }
 
  void on_stop()
  { test_comment("tx_thread::on_stop()"); }
 
  bool on_loop()
  {
    thread::usleep(1000000);
    if(fifo.size() > 10) {
      test_comment("tx_thread::on_loop(): exit fifo.size() > 10");
      return false;
    } else {
      test_comment("tx_thread::on_loop(): put " << counter);
      fifo.put(counter++);
      return true;
    }
    return false;
  }
 
public:
 
  int counter;
};
 
class rx_thread : public thread
{
public:
 
  rx_thread() : thread()
  { test_comment("rx_thread::rx_thread()"); thread::start(); }
 
  explicit rx_thread(int initial) : thread()
  { (void) initial; test_comment("rx_thread::rx_thread()"); thread::start(); }
 
  virtual ~rx_thread()
  { test_comment("rx_thread::~rx_thread()"); }
 
protected:
 
  void on_start()
  { test_comment("rx_thread::on_start()"); }
 
  void on_stop()
  { test_comment("rx_thread::on_stop()"); }
 
  bool on_loop()
  {
    if(!fifo.empty()) {
      int i = fifo.get();
      test_comment("rx_thread::on_loop(): received " << i);
    } else {
      test_comment("rx_thread::on_loop(): received nothing");
      thread::usleep(100000);
    }
    return true;
  }
};
 
static void test_thread()
{
  tx_thread tx1(0);
  tx_thread tx2(1000);
  rx_thread rx1;
  thread::usleep(500000);
 
  test_expect(tx1.running());
  test_expect(tx2.running());
  test_expect(rx1.running());
 
  int counter = 0;
  while(rx1.running()) {
    thread::usleep(100000);
    if(++counter > 20) {
      test_comment("Stopping tx1");
      tx1.stop();
      test_comment("Stopping tx2");
      tx2.stop();
      test_comment("Stopping rx1");
      rx1.stop();
      test_comment("done");
      break;
    }
  }
  test_comment("done");
  test_expect(tx1.counter > 0);
  test_expect(tx2.counter > 0);
}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
// test main
//
void test()
{
  test_lock();
  test_autolock();
  test_synchronized();
  test_fifo();
  test_thread();
}

Quelltext

Source code

/**
 * @package de.atwillys.cc.swl
 * @license BSD (simplified)
 * @author Stefan Wilhelm (stfwi)
 * @standard c++98
 *
 * @file thread.hh
 * @ccflags
 * @ldflags -lpthread
 * @platform linux, bsd, windows
 * @standard >= c++98
 *
 * -----------------------------------------------------------------------------
 *
 * Threading and thread synchronisation classes:
 *
 *  - class sw::thread:
 *
 *      Simple thread handling by extending this class and overloading the methods
 *      on_loop(), on_start() and on_stop():
 *
 *        class mythread : public sw::thread
 *        {
 *        public:
 *          mythread() : sw::thread(), counter(0)   { ; }
 *          virtual ~mythread()  { ; }
 *        protected:
 *          void on_start()
 *          { cout << "Thread started: " << thread::current_thread() << endl; }
 *
 *          void on_stop()
 *          { cout << "Thread stopped: " << thread::current_thread() << endl; }
 *
 *          bool on_loop()
 *          { thread::sleep(100); ++counter; cout << "Thread running: " <<
 *            (long)thread::current_thread() << " " << counter << endl; return true;
 *          }
 *
 *          int counter;
 *        };
 *
 *        [...]
 *        mythread thread;
 *        if(!thread.start()) { error ...  }
 *        thread.stop();
 *        if(thread.running()) { ... }
 *        if(thread.stopped()) { ... }
 *        if(thread.id() == ...) { ... }
 *        sw::thread::sleep(milliseconds);
 *        unsigned long this_thread_id = sw::thread::current_thread();
 *
 *      ------------------------------------------------------------------------
 *
 * - class sw::sync::lock
 *
 *      Simple mutex/crirical section based lock. methods: lock(), unlock(), trylock().
 *      For two mutex: lock2(), unlock2()
 *
 *      ------------------------------------------------------------------------
 *
 * - class sw::sync::autolock
 *
 *      Used in conjunction with sw::sync::lock. Automatically locks a sw::sync::lock
 *      passed in the constructor and unlocks in the destructor. Additional methods
 *      allow to unlock/relock earlier.
 *
 *      ------------------------------------------------------------------------
 *
 * - class sw::sync::flag
 *
 *      Simple synchronised boolean like variable, which allows to be waited for
 *      with timeout. Under Windows known as SetEvent/WaitEvent, under *nix realised
 *      with thread conditions.
 *
 *      ------------------------------------------------------------------------
 *
 * - class template sw::sync::fifo<data type, container type= default deque>
 *
 *     Synchronised (auto locked) fifo.
 *
 *      ------------------------------------------------------------------------
 *
 * - class template sw::sync::synchronised<data type>
 *
 *     Synchronised (auto locked) primitive type.
 *
 * -----------------------------------------------------------------------------
 * +++ BSD license header +++
 * Copyright (c) 2008-2014, Stefan Wilhelm (stfwi, <cerbero s@atwilly s.de>)
 * All rights reserved.
 * 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.
 * (3) Neither the name of atwillys.de nor the names of its contributors may be
 * used to endorse or promote products derived from this software without specific
 * prior written permission. 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 SW_THREAD_HH
#define SW_THREAD_HH
 
// <editor-fold desc="includes/debug output" defaultstate="collapsed">
#if defined(OS_WIN) || defined(__MSC_VER) || defined(_WIN32) || defined (_WINDOWS_)
#include <windows.h>
#ifndef OS_WIN
#define OS_WIN
#endif
#define TID_INV INVALID_HANDLE_VALUE
#else
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#define TID_INV 0
#endif
#include <deque>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <exception>
 
#if defined THREAD_DEBUG || defined THREAD_DEBUG2
#include <cstdio>
#include <stdarg.h>
template <typename char_t> static void thread_trace(const char_t* ptrn, ...)
{ va_list args; va_start(args, ptrn); vfprintf(stderr, ptrn, args);
  fprintf(stderr, "\n"); fflush(stderr); va_end(args); }
#else
template <typename char_t> static inline void thread_trace(const char_t*, ...) {;}
#endif
#undef ctrace
#undef ctracem
#undef ctracem2
#define ctrace thread_trace
#define ctracem thread_trace
#ifdef THREAD_DEBUG2
#define ctracem2 thread_trace
#else
#define ctracem2(X)
#endif
// </editor-fold>
 
// <editor-fold desc="basic_lock" defaultstate="collapsed">
/**
 * Simple mutex based lock. Contains mutable variables, so that the methods can be
 * const (to be used in const methods of classes including the basic_lock to read only).
 */
namespace sw { namespace detail {
template <typename T=int>
class basic_lock
{
#ifdef OS_WIN
public:
 
  inline basic_lock()
  { try{::InitializeCriticalSection(&cs_);} catch(...) {}}
 
  virtual ~basic_lock()
  { try{ ::DeleteCriticalSection(&cs_); } catch(...) {;} }
 
  inline bool lock() const throw()
  { try{::EnterCriticalSection(&cs_); return true;} catch(...) {return false;} }
 
  inline bool unlock() const throw()
  { try{::LeaveCriticalSection(&cs_); return true;} catch(...) {return false;} }
 
  inline bool trylock() const throw()
  { try{ return ::TryEnterCriticalSection(&cs_) != 0;} catch(...) {return false;} }
 
  inline bool corrupt() const throw()
  { return false; }
 
private:
  mutable CRITICAL_SECTION cs_;
 
#else
public:
 
  inline basic_lock()
  {
    ctracem2("basic_lock::basic_lock()");
    if(::pthread_mutexattr_init(&attr_)
    || ::pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE)
    || ::pthread_mutex_init(&cs_, &attr_)) {
      memset(&cs_, 0, sizeof(pthread_mutex_t));
    }
  }
 
  virtual ~basic_lock()
  { ctracem2("basic_lock::~basic_lock()"); ::pthread_mutex_destroy(&cs_); }
 
  inline bool lock() const throw()
  { ctracem2("basic_lock::lock()"); return !::pthread_mutex_lock(&cs_); }
 
  inline bool unlock() const throw()
  { ctracem2("basic_lock::unlock()"); return !::pthread_mutex_unlock(&cs_); }
 
  inline bool trylock() const throw()
  { ctracem2("basic_lock::trylock()"); return !::pthread_mutex_trylock(&cs_); }
 
  inline bool corrupt() const throw()
  {
    ctracem2("basic_lock::corrupt()");
    for(unsigned i=0; i<sizeof(pthread_mutex_t); ++i) {
      if(((const char*)(&cs_))[i]) return false;
    }
    return true;
  }
 
private:
 
  pthread_mutexattr_t attr_;
  mutable pthread_mutex_t cs_;
 
#endif
 
  #if(0) /* unused */
  bool lock2(const basic_lock & other_cs) const throw()
  {
    ctracem2("basic_lock::lock2()");
    while(true) {
      if(!lock()) return false;
      if(other_cs.trylock()) return true;
      if(!unlock()) return false;
    }
  }
 
  bool unlock2(const basic_lock & other_cs) const throw()
  { ctracem2("basic_lock::unlock2()"); return (other_cs.unlock()?1:0) & (unlock()?1:0); }
  #endif
 
};
}}
// </editor-fold>
 
// <editor-fold desc="basic_autolock" defaultstate="collapsed">
/**
 * Auto lock class template, locks in constructor, unlocks in destructor (if not
 * already unlocked)
 */
namespace sw { namespace detail {
template <typename lock_type=basic_lock<> >
class basic_autolock
{
public:
 
  explicit inline basic_autolock(lock_type &lck) throw() : locked_(false), lock_(lck)
  { ctracem2("basic_autolock::basic_autolock()"); lock(); }
 
  virtual ~basic_autolock() throw()
  { ctracem2("basic_autolock::~basic_autolock()"); unlock(); }
 
  inline bool locked() const throw()
  { ctracem2("basic_autolock::locked()"); return locked_; }
 
  inline bool lock() const throw()
  { ctracem2("basic_autolock::lock()"); return (locked_ = lock_.lock()); }
 
  inline bool unlock() const throw()
  { ctracem2("basic_autolock::unlock()"); return !(locked_ &= !lock_.unlock()); }
 
protected:
 
  inline basic_autolock() : locked_(false), lock_()
  { }
 
  mutable bool locked_;
  lock_type & lock_;
};
}}
// </editor-fold>
 
// <editor-fold desc="specialisations" defaultstate="collapsed">
namespace sw { namespace sync {
  typedef sw::detail::basic_lock<> lock;
  typedef sw::detail::basic_autolock<> autolock;
}}
// </editor-fold>
 
// <editor-fold desc="fifo" defaultstate="collapsed">
/**
 * Fifo class template
 */
namespace sw { namespace sync {
template<typename Value_Type, typename Container_Type=std::deque<Value_Type> >
class fifo
{
public:
 
  typedef Value_Type value_type;
  typedef Container_Type container_type;
 
  #ifdef SW_FIFO_STD_EXCEPTION
  class exception_type : public std::exception {
    private: const char* s_;
    public : explicit exception_type(const char *p) : s_(p) { ; }
    public : const char* what() const throw() { return s_ ? s_ : ""; }
  };
  #define lock_failed exception_type("Fifo: lock failed");
  #define fifo_empty exception_type("Fifo: empty");
  #define data_error exception_type("Fifo: data error");
  #else
  typedef enum { ok = 0, fifo_empty, lock_failed, data_error } exception_type;
  #endif
 
  #define lock_fifo() autolock_type alck(cs_); if(!alck.locked()){throw lock_failed;}
  #define fwd_dex(CODE) try { CODE; } catch(...) { throw data_error; }
 
  inline fifo() : cs_(), ct_()
  {}
 
  virtual ~fifo()
  { ct_.clear(); cs_.unlock(); }
 
  inline bool empty() const
  { lock_fifo(); fwd_dex(return ct_.empty();) }
 
  inline void clear()
  { lock_fifo(); fwd_dex(ct_.clear();) }
 
  inline unsigned long size() const
  { lock_fifo(); fwd_dex(return (unsigned long) ct_.size();) }
 
  inline value_type first() const
  {
    lock_fifo();
    if(ct_.empty()) throw fifo_empty;
    fwd_dex(return ct_.front();)
  }
 
  inline value_type last() const
  {
    lock_fifo();
    if(ct_.empty()) throw fifo_empty;
    fwd_dex(return ct_.back();)
  }
 
  inline container_type copy() const
  {
    lock_fifo(); fwd_dex(return ct_;)
  }
 
  inline void put(const value_type & data)
  {
    lock_fifo();
    fwd_dex(ct_.push_back(data);)
  }
 
  inline value_type get()
  {
    lock_fifo();
    if(ct_.empty()) throw fifo_empty;
    fwd_dex(
      value_type r = ct_.front();
      ct_.pop_front();
      return r;
    )
  }
 
  unsigned long get(container_type & c, unsigned long n=0)
  {
    lock_fifo();
    fwd_dex(
      if(n==0 || n <= ct_.size()) {
        n = (unsigned long) ct_.size();
        typename container_type::const_iterator it;
        for(it=ct_.begin(); it<ct_.end(); ++it) c.push_back(*it);
        ct_.clear();
        return n;
      }
      unsigned long i=0;
      while(i<n) { c.push_back(ct_.front()); ct_.pop_front(); if(++i >= n) break;}
      return i;
    );
  }
 
  #undef lock_fifo
  #undef fwd_dex
  #ifdef SW_FIFO_STD_EXCEPTION
  #undef lock_failed
  #undef fifo_empty
  #undef data_error
  #endif
 
protected:
  typedef lock lock_type;
  typedef autolock autolock_type;
  mutable lock_type cs_;
  container_type ct_;
};
}}
// </editor-fold>
 
// <editor-fold desc="synchronized" defaultstate="collapsed">
namespace sw { namespace sync {
template<typename T>
class synchronized
{
public:
 
  inline synchronized()
  {}
 
  explicit inline synchronized(const T& initval) : value_(initval)
  {}
 
  virtual ~synchronized()
  {}
 
  inline void operator = (T value)
  { set(value); }
 
  inline synchronized& operator = (const synchronized& rf)
  { set(rf.get()); return *this; }
 
  inline operator T () const
  { return get(); }
 
  inline void set(const T& value)
  { detail::basic_autolock<> al(cs_); value_ = value; }
 
  inline T get() const
  { detail::basic_autolock<> al(cs_); return value_; }
 
private:
 
  volatile T value_;
  mutable detail::basic_lock<> cs_;
};
}}
// </editor-fold>
 
// <editor-fold desc="basic_thread" defaultstate="collapsed">
namespace sw { namespace detail {
template <typename Id_Type=unsigned long>
class basic_thread
{
protected:
 
  typedef Id_Type id_type;
 
  /**
   * This mehod is to be overloaded. The framing threadFunction()
   * organizes the starting, stopping and suspending. The task()
   * is a method of the extended thread class, so the this pointer
   * is in scope.
   * return false if the thread is to be exited
   */
  virtual void on_start() {}
  virtual void on_stop()  {}
  virtual bool on_loop() = 0;
 
  /**
   * Constructor / destructor
   */
  #ifdef OS_WIN
  basic_thread() : tid_(TID_INV), state_(0) { ; }
  virtual ~basic_thread() {if(tid_ != TID_INV) {::TerminateThread(tid_, 0); ::CloseHandle(tid_);}}
  #else
 
  basic_thread() : tid_(TID_INV), state_(0)
  { ctracem("basic_thread::basic_thread([constructed from thread=%d])", current_thread()); }
 
  basic_thread(const basic_thread&)
  {;}
 
  void operator = (const basic_thread&)
  {;}
 
  virtual ~basic_thread()
  {
    ctracem("basic_thread::~basic_thread([%d, from=%d])", tid_, current_thread());
    if(state_ < 2) state_ = 2;
    if(tid_) ::pthread_join(tid_, NULL);
  }
  #endif
 
public:
 
  /**
   * Starts the thread. Returns success.
   */
  bool start()
  {
    ctracem("basic_thread::start()");
    if(tid_!=TID_INV || state_) return false; // already running
    #ifdef OS_WIN
    DWORD ec;
    tid_ = ::CreateThread(NULL,0,thread_function, this, 0, &ec);
    if(tid_==NULL || tid_==TID_INV) { tid_ = TID_INV; return false; }
    state_ = 1; // running
    return true;
    #else
    int r = ::pthread_create(&tid_, NULL, thread_function, this);
    switch(r) {
      case 0: state_ = 1; return true;
      case EAGAIN: ctrace("basic_thread::start(): EAGAIN"); break;
      case EINVAL: ctrace("basic_thread::start(): EINVAL"); break;
      case EPERM:  ctrace("basic_thread::start(): EPERM"); break;
      default:     ctrace("basic_thread::start(): ERROR %d", r); break;
    }
    state_ = 3;
    return false;
    #endif
  }
 
  /**
   * Stops the thread.
   */
  void stop()
  {
    ctracem("basic_thread::stop()");
    #ifdef OS_WIN
    state_ = 2;
    if(basic_thread::thread_id() == basic_thread::current_thread()) return;
    for(int t=0; t<50; t++) { usleep(2000); if(!running()) return; }
    if(tid_ != TID_INV) { ::TerminateThread(tid_, 0); ::CloseHandle(tid_); }
    tid_ = TID_INV;
    state_ = 3;
    #else
    if(!tid_ || state_ >= 3) return;
    state_ = 2; // should close
    if(basic_thread::thread_id() == basic_thread::current_thread()) return;
    ::pthread_join(tid_, NULL); // wait aborted and detatch resources
    state_ = 3;
    #endif
  }
 
  /**
   * Returns true if the thread is running
   * @return bool
   */
  inline bool running() const
  { return tid_!=TID_INV && state_ < 3;}
 
  /**
   * Returns true if the thread is stopped
   * @return bool
   */
  inline bool stopped() const
  { return tid_==TID_INV || state_ == 3;}
 
  /**
   * Returns the id of the objects thread.
   * @return id_type
   */
  inline id_type thread_id() const throw()
  {
    #ifdef OS_WIN
    return (id_type) GetThreadId(tid_);
    #else
    return (id_type) tid_;
    #endif
  }
 
  /**
   * Returns the id of the current thread
   * @return id_type
   */
  static inline id_type current_thread()
  {
    #ifdef OS_WIN
    return (id_type) ::GetCurrentThreadId();
    #else
    return (id_type) ::pthread_self();
    #endif
  }
 
  /**
   * Sleep current thread
   * @param unsigned ms
   */
  static void usleep(unsigned long us)
  {
    #ifdef OS_WIN
    ::Sleep((DWORD)(us/1000));
    #else
    ::usleep((useconds_t)us);
    #endif
  }
 
  #ifdef OS_WIN
  static DWORD WINAPI thread_function(LPVOID pParam)
  {
    basic_thread* me = reinterpret_cast<basic_thread*>(pParam);
    if(!me) return 0;
    HANDLE tid = me->tid_;
    try {
      me->on_start();
      while(me->state_ < 2 && me->on_loop());
    } catch (const std::exception & e) {
      ctrace("basic_thread::thread_function([%d]): Exception in on_start/loop(): %s", tid, e.what());
    } catch(...) {
      ctrace("basic_thread::thread_function([%d]): Exception in on_start/loop()", tid);
    }
    try {
      me->on_stop();
    } catch (const std::exception & e) {
      ctrace("basic_thread::thread_function([%d]): Exception in on_loop(): %s", tid, e.what());
    } catch(...) {
      ctrace("basic_thread::thread_function([%d]): Exception in on_loop()", tid);
    }
    me->state_ = 3;
    return 0;
  }
  #else
  static void * thread_function(void* pParam)
  {
    ::pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    ::pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    basic_thread* me = reinterpret_cast<basic_thread*>(pParam);
    if(!me) return 0;
    ctrace("basic_thread::thread_function([%d]): starting", basic_thread::current_thread());
    id_type tid = (id_type)me->tid_;
    try {
      me->on_start();
      while(me->state_ < 2 && me->on_loop());
    } catch (const std::exception & e) {
      ctrace("basic_thread::thread_function([%x]): Exception in on_start/loop(): %s", tid, e.what());
    } catch(...) {
      ctrace("basic_thread::thread_function([%x]): Exception in on_start/loop()", tid);
    }
    try {
      me->on_stop();
    } catch (const std::exception & e) {
      ctrace("basic_thread::thread_function([%x]): Exception in on_loop(): %s", tid, e.what());
    } catch(...) {
      ctrace("basic_thread::thread_function([%x]): Exception in on_loop()", tid);
    }
    me->state_ = 3;
    ctrace("basic_thread::thread_function([%x]): stopped", tid);
    ::pthread_exit(0);
    return 0;
  }
  #endif
 
private:
 
  #ifdef OS_WIN
  HANDLE tid_;
  #else
  pthread_t tid_; // Used read-only, except when creating the thread, so not interlocked
  #endif
  ::sw::sync::synchronized<unsigned> state_; // Read/written potentially everywhere
};
}}
namespace sw {
  typedef sw::detail::basic_thread<> thread;
}
// </editor-fold>
 
// <editor-fold desc="undefs" defaultstate="collapsed">
#undef TID_INV
#undef ctrace
#undef ctracem
#undef ctracem2
// </editor-fold>
#endif