/* =============================================================================
* scpp_thread.cpp
* Copyright (c) 2003 - 2011 Nomura Kei
* LICENSE :
* LGPL (GNU Lesser General General Public License - Version 3,29 June 2007)
* http://www.gnu.org/copyleft/lesser.html
* =============================================================================
*
* ライブラリの動的ロードを行うモジュール
*
*/
#include <scpp_os.hpp>
#include <scpp_thread.hpp>
namespace
{
} // namespace 無名名前空間
namespace scpp
{
////////////////////////////////////////////////////////////////////////////////
//
// ThreadException
//
/**
* 最後に発生した errno に対するメッセージをもつ Exception を構築します.
* エラーメッセージを取得できない場合, 空文字がメッセージに設定されます.
*/
ThreadException::ThreadException() throw() : Exception()
{
}
/**
* コピーコンストラクタ.
*
* @param t コピー元
*/
ThreadException::ThreadException(const ThreadException& t) throw() : Exception(t)
{
}
/**
* 指定されたメッセージをもつ ThreadException を構築します.
*
* @param msg メッセージ
*/
ThreadException::ThreadException(const std::string& msg) throw() : Exception(msg)
{
}
/**
* デストラクタ.
*/
ThreadException::~ThreadException() throw()
{
}
////////////////////////////////////////////////////////////////////////////////
//
// Thread
//
/**
* スレッドを構築します.
*/
Thread::Thread() : runnable(0), aliveState(false)
{
// NOP
}
/**
* スレッドを構築(コピー)します.
*
* @param t コピー元
*/
Thread::Thread(const Thread& t) : runnable(t.runnable), aliveState(t.aliveState)
{
// NOP
}
/**
* 指定された Runnable を実行するスレッドを構築します.
*
* @param r スレッドで実行する Runnable
*/
Thread::Thread(Runnable* r) : runnable(r), aliveState(false)
{
// NOP
}
/**
* スレッドを破棄します.
*/
Thread::~Thread()
{
// NOP
}
/**
* スレッドが生きているか否かを返します.
*
* @return ture/false (スレッドが生存している/していない)
*/
bool Thread::isAlive()
{
return aliveState;
}
/**
* スレッドで実行される関数.
*/
void Thread::run()
{
if (runnable != 0)
{
runnable->run();
}
}
/**
* スレッドを開始します.
*/
void Thread::start()
{
if (aliveState) {
throw ThreadException("already running");
}
aliveState = true;
bool ret = createThread();
if (!ret)
{
aliveState = false;
throw ThreadException();
}
}
/**
* スレッドが終了するのを待機します.
*/
void Thread::join()
{
#if (SCPP_IS_WINDOWS)
WaitForSingleObject(tid, INFINITE);
CloseHandle(tid);
#else
pthread_join(tid, 0);
#endif
}
/**
* 指定された ms 間スリープします。
*
* @param time スリープする時間(ms)
*/
void Thread::sleep(long time)
{
#if (SCPP_IS_WINDOWS)
Sleep(time);
#else
struct timespec req;
long sec = time / 1000;
long msec = time - (sec * 1000);
req.tv_sec = sec;
req.tv_nsec = msec * 1000000;
nanosleep(&req, 0);
#endif
}
/**
* スレッドを生成します.
*
* @return スレッドのハンドル
*/
bool Thread::createThread()
{
#if (SCPP_IS_WINDOWS)
threadId = 0;
tid = (thread_t) _beginthreadex(
0,
0,
&Thread::executeThread,
this,
0,
&threadId);
return (tid != 0);
#else
int ret = pthread_create(&tid, 0, &Thread::executeThread, this);
return (ret == 0);
#endif
}
/**
* スレッド実行用関数
* 本関数は, Thread::start メソッドからのみ実行されます.
*
* @param args Thread ポインタ
*/
#if (SCPP_IS_WINDOWS)
unsigned __stdcall Thread::executeThread(void* args)
{
scpp::Thread* thread = reinterpret_cast<scpp::Thread*>(args);
thread->run();
thread->aliveState = false;
// _endthreadex は自動で呼び出されるので省略.
// _endthreadex(0);
return 0;
}
#else
void* Thread::executeThread(void* args)
{
scpp::Thread* thread = reinterpret_cast<scpp::Thread*>(args);
thread->run();
thread->aliveState = false;
// pthread_exit(0);
return 0;
}
#endif
////////////////////////////////////////////////////////////////////////////////
//
// Mutex
//
/**
* Mutex を構築します.
*/
Mutex::Mutex()
{
#if (SCPP_IS_WINDOWS)
mutex = CreateMutex(0, false, 0);
#else
pthread_mutex_init(&mutex, 0);
#endif
}
/**
* Mutex を破棄します.
*/
Mutex::~Mutex()
{
#if (SCPP_IS_WINDOWS)
CloseHandle(mutex);
#else
pthread_mutex_destroy(&mutex);
#endif
}
/**
* ロックします.
*/
void Mutex::lock()
{
#if (SCPP_IS_WINDOWS)
WaitForSingleObject(mutex, INFINITE);
#else
pthread_mutex_lock(&mutex);
#endif
}
/**
* ロックを解除します.
*/
void Mutex::unlock()
{
#if (SCPP_IS_WINDOWS)
ReleaseMutex(mutex);
#else
pthread_mutex_unlock(&mutex);
#endif
}
} // namespace scpp