📄 omnithread.h
字号:
public:
omni_semaphore(unsigned int initial = 1);
~omni_semaphore(void);
void wait(void);
// if semaphore value is > 0 then decrement it and carry on. If it's
// already 0 then block.
int trywait(void);
// if semaphore value is > 0 then decrement it and return 1 (true).
// If it's already 0 then return 0 (false).
void post(void);
// if any threads are blocked in wait(), wake one of them up. Otherwise
// increment the value of the semaphore.
private:
// dummy copy constructor and operator= to prevent copying
omni_semaphore(const omni_semaphore&);
omni_semaphore& operator=(const omni_semaphore&);
OMNI_THREAD_EXPOSE:
OMNI_SEMAPHORE_IMPLEMENTATION
};
//
// A helper class for semaphores, similar to omni_mutex_lock above.
//
class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
omni_semaphore& sem;
public:
omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
~omni_semaphore_lock(void) { sem.post(); }
private:
// dummy copy constructor and operator= to prevent copying
omni_semaphore_lock(const omni_semaphore_lock&);
omni_semaphore_lock& operator=(const omni_semaphore_lock&);
};
///////////////////////////////////////////////////////////////////////////
//
// Thread
//
///////////////////////////////////////////////////////////////////////////
class _OMNITHREAD_NTDLL_ omni_thread {
public:
enum priority_t {
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH
};
enum state_t {
STATE_NEW, // thread object exists but thread hasn't
// started yet.
STATE_RUNNING, // thread is running.
STATE_TERMINATED // thread has terminated but storage has not
// been reclaimed (i.e. waiting to be joined).
};
//
// Constructors set up the thread object but the thread won't start until
// start() is called. The create method can be used to construct and start
// a thread in a single call.
//
omni_thread(void (*fn)(void*), void* arg = NULL,
priority_t pri = PRIORITY_NORMAL);
omni_thread(void* (*fn)(void*), void* arg = NULL,
priority_t pri = PRIORITY_NORMAL);
// these constructors create a thread which will run the given function
// when start() is called. The thread will be detached if given a
// function with void return type, undetached if given a function
// returning void*. If a thread is detached, storage for the thread is
// reclaimed automatically on termination. Only an undetached thread
// can be joined.
void start(void);
// start() causes a thread created with one of the constructors to
// start executing the appropriate function.
protected:
omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
// this constructor is used in a derived class. The thread will
// execute the run() or run_undetached() member functions depending on
// whether start() or start_undetached() is called respectively.
void start_undetached(void);
// can be used with the above constructor in a derived class to cause
// the thread to be undetached. In this case the thread executes the
// run_undetached member function.
virtual ~omni_thread(void);
// destructor cannot be called by user (except via a derived class).
// Use exit() or cancel() instead. This also means a thread object must
// be allocated with new - it cannot be statically or automatically
// allocated. The destructor of a class that inherits from omni_thread
// shouldn't be public either (otherwise the thread object can be
// destroyed while the underlying thread is still running).
public:
void join(void**);
// join causes the calling thread to wait for another's completion,
// putting the return value in the variable of type void* whose address
// is given (unless passed a null pointer). Only undetached threads
// may be joined. Storage for the thread will be reclaimed.
void set_priority(priority_t);
// set the priority of the thread.
static omni_thread* create(void (*fn)(void*), void* arg = NULL,
priority_t pri = PRIORITY_NORMAL);
static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
priority_t pri = PRIORITY_NORMAL);
// create spawns a new thread executing the given function with the
// given argument at the given priority. Returns a pointer to the
// thread object. It simply constructs a new thread object then calls
// start.
static void exit(void* return_value = NULL);
// causes the calling thread to terminate.
static omni_thread* self(void);
// returns the calling thread's omni_thread object. If the
// calling thread is not the main thread and is not created
// using this library, returns 0. (But see create_dummy()
// below.)
static void yield(void);
// allows another thread to run.
static void sleep(unsigned long secs, unsigned long nanosecs = 0);
// sleeps for the given time.
static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
unsigned long rel_sec = 0, unsigned long rel_nsec=0);
// calculates an absolute time in seconds and nanoseconds, suitable for
// use in timed_waits on condition variables, which is the current time
// plus the given relative offset.
static void stacksize(unsigned long sz);
static unsigned long stacksize();
// Use this value as the stack size when spawning a new thread.
// The default value (0) means that the thread library default is
// to be used.
// Per-thread data
//
// These functions allow you to attach additional data to an
// omni_thread. First allocate a key for yourself with
// allocate_key(). Then you can store any object whose class is
// derived from value_t. Any values still stored in the
// omni_thread when the thread exits are deleted.
//
// These functions are NOT thread safe, so you should be very
// careful about setting/getting data in a different thread to the
// current thread.
typedef unsigned int key_t;
static key_t allocate_key();
class value_t {
public:
virtual ~value_t() {}
};
value_t* set_value(key_t k, value_t* v);
// Sets a value associated with the given key. The key must
// have been allocated with allocate_key(). If a value has
// already been set with the specified key, the old value_t
// object is deleted and replaced. Returns the value which was
// set, or zero if the key is invalid.
value_t* get_value(key_t k);
// Returns the value associated with the key. If the key is
// invalid, or there is no value for the key, returns zero.
value_t* remove_value(key_t k);
// Removes the value associated with the key and returns it.
// If the key is invalid, or there is no value for the key,
// returns zero.
// Dummy omni_thread
//
// Sometimes, an application finds itself with threads created
// outside of omnithread which must interact with omnithread
// features such as the per-thread data. In this situation,
// omni_thread::self() would normally return 0. These functions
// allow the application to create a suitable dummy omni_thread
// object.
static omni_thread* create_dummy(void);
// creates a dummy omni_thread for the calling thread. Future
// calls to self() will return the dummy omni_thread. Throws
// omni_thread_invalid if this thread already has an
// associated omni_thread (real or dummy).
static void release_dummy();
// release the dummy omni_thread for this thread. This
// function MUST be called before the thread exits. Throws
// omni_thread_invalid if the calling thread does not have a
// dummy omni_thread.
// class ensure_self should be created on the stack. If created in
// a thread without an associated omni_thread, it creates a dummy
// thread which is released when the ensure_self object is deleted.
class ensure_self {
public:
inline ensure_self() : _dummy(0)
{
_self = omni_thread::self();
if (!_self) {
_dummy = 1;
_self = omni_thread::create_dummy();
}
}
inline ~ensure_self()
{
if (_dummy)
omni_thread::release_dummy();
}
inline omni_thread* self() { return _self; }
private:
omni_thread* _self;
int _dummy;
};
private:
virtual void run(void* /*arg*/) {}
virtual void* run_undetached(void* /*arg*/) { return NULL; }
// can be overridden in a derived class. When constructed using the
// the constructor omni_thread(void*, priority_t), these functions are
// called by start() and start_undetached() respectively.
void common_constructor(void* arg, priority_t pri, int det);
// implements the common parts of the constructors.
omni_mutex mutex;
// used to protect any members which can change after construction,
// i.e. the following 2 members.
state_t _state;
priority_t _priority;
static omni_mutex* next_id_mutex;
static int next_id;
int _id;
void (*fn_void)(void*);
void* (*fn_ret)(void*);
void* thread_arg;
int detached;
int _dummy;
value_t** _values;
unsigned long _value_alloc;
omni_thread(const omni_thread&);
omni_thread& operator=(const omni_thread&);
// Not implemented
public:
priority_t priority(void) {
// return this thread's priority.
omni_mutex_lock l(mutex);
return _priority;
}
state_t state(void) {
// return thread state (invalid, new, running or terminated).
omni_mutex_lock l(mutex);
return _state;
}
int id(void) { return _id; }
// return unique thread id within the current process.
// This class plus the instance of it declared below allows us to execute
// some initialisation code before main() is called.
class _OMNITHREAD_NTDLL_ init_t {
public:
init_t(void);
~init_t(void);
};
friend class init_t;
friend class omni_thread_dummy;
OMNI_THREAD_EXPOSE:
OMNI_THREAD_IMPLEMENTATION
};
#ifndef __rtems__
static omni_thread::init_t omni_thread_init;
#else
// RTEMS calls global Ctor/Dtor in a context that is not
// a posix thread. Calls to functions to pthread_self() in
// that context returns NULL.
// So, for RTEMS we will make the thread initialization at the
// beginning of the Init task that has a posix context.
#endif
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -