thread

今んとこWindowsだけ :b

宣言

ヘッダーファイル:roast/thread.hpp

  1. typedef int (*roast_thread_callback_t)(int);
  2. namespace roast
  3. {
  4. class thread_exception : public ::std::string
  5. {
  6. public:
  7. thread_exception(const char* msg) : ::std::string(msg) {}
  8. thread_exception(const ::std::string &s) : ::std::string(s) {}
  9. };
  10. template <typename _Impl>
  11. class thread_
  12. {
  13. public:
  14. thread_();
  15. thread_(roast_thread_func_t func, int param=0, void* opt=NULL);
  16. template <typename T> thread_(const T &cls, int param=0, void* opt=NULL);
  17. template <typename T> thread_(T *ptr, int param=0, void* opt=NULL);
  18. template <typename T> thread_(int (T::*func)(int), T *ptr, int param=0, void* opt=NULL);
  19. bool start_func(roast_thread_func_t func, int param=0, void* opt=NULL);
  20. template <typename T> bool start_class(const T &cls, int param=0, void* opt=NULL);
  21. template <typename T> bool start_class_ptr(T *ptr, int param=0, void* opt=NULL);
  22. template <typename T> bool start_class_ptr(int (T::*func)(int), T *ptr, int param=0, void* opt=NULL);
  23. bool start(roast_thread_func_t func, int param=0, void* opt=NULL);
  24. template <typename T> bool start(const T &cls, int param=0, void* opt=NULL);
  25. template <typename T> bool start(T *ptr, int param=0, void* opt=NULL);
  26. template <typename T> bool start(int (T::*func)(int), T *ptr, int param=0, void* opt=NULL);
  27. bool release();
  28. bool join(unsigned int timeout_ms=-1);
  29. bool is_alive();
  30. int get_result();
  31. void* get_native_handle();
  32. };
  33. #ifdef WIN32
  34. typedef thread_< _thread_impl_win32> thread;
  35. #endif//WIN32
  36. }

使い方

  1. ::roast::thread hoge_thread(any_func);

のようにする事により、関数 any_func() をコールバック関数として使用したスレッドを起動します。
コールバック関数の型は

  1. typedef int (*roast_thread_callback_t)(int);

としてtypedefされており、一つのint型引数を取り、intを復帰する関数(ないしそれに相当する関数をキャストしたもの)である必要があります。

このコールバック関数のint型引数には、上記例では0が渡されますが

  1. roast::thread hoge_thread(any_func,10);

のように、第二パラメータを指定する事により、第二パラメータの値が渡されるようになります。(上記例では10)
複数のパラメータを渡したい場合には、それらを構造体化し、ポインタを渡すようにします。


引数なしコンストラクタを用いたい場合(startメソッド)

引数なしコンストラクタを用いたい場合は、

  1. roast::thread hoge_thread;
  2. hoge_thread.start(any_func,10);

のように、start()メソッドを使用します。

スレッドの終了待ち

  1. hoge_thread.join(1000);

join()メソッドを使用することにより、スレッドの終了を待機する事が出来ます。
引数として指定しているのは、終了待ちのタイムアウト時間(ミリ秒)です。
省略、または-1を指定した場合には無限に待ちます。

タイムアウト時間を経過してもスレッドが終了しなかった場合(及びもしくは何らかのエラーが有った場合)、join()メソッドはfalseを返します。
タイムアウト時間内にスレッドが終了した場合にはtrueを返します。


スレッドの生存状態の取得

スレッドの生存状態(コールバック関数が既に終了状態にあるかどうか)を取得するには、is_alive()メソッドを使用します。
is_alive()メソッドは、スレッドがまだ生存状態にある場合にはtrueを、終了している場合にはfalseを返します。


コールバック関数の復帰値の取得

get_result()メソッドを使用することにより取得できます。


クラス内メソッドの起動(staticメソッド)

  1. class CHoge
  2. {
  3. public:
  4. static int Hoge(int b)
  5. {
  6. return printf("%d\n", b);
  7. }
  8. };
  9. void main( void )
  10. {
  11. roast::thread th(CHoge::Hoge,10);
  12. th.join();
  13. }

のようにすれば、クラス内のstaticメソッドを起動する事も可能です。


クラス内メソッドの起動(非staticメソッド)

メソッドが非staticである場合、第二引数としてそのクラスのインスタンスへのポインタを指定する必要があります。

  1. class CHoge
  2. {
  3. public:
  4. int m_a;
  5. CHoge(int a){ m_a = a; }
  6. int Hoge(int)
  7. {
  8. return printf("%d\n", m_a);
  9. }
  10. };
  11. void main( void )
  12. {
  13. CHoge(10) hoge;
  14. roast::thread a(&CHoge::Hoge, &hoge);
  15. a.join();
  16. }

またコンパイラによっては上記の第一引数のように、メンバ関数ポインタへの&の付加が求められる場合もあります。


クラス内メソッドの起動(関数オブジェクト)

関数の代わりに関数オブジェクトを指定する事も出来ます。

  1. class CHoge
  2. {
  3. public:
  4. int m_a;
  5. CHoge(int a){ m_a = a; }
  6. int operator()(int)
  7. {
  8. return printf("%d\n", m_a);
  9. }
  10. };
  11. void main( void )
  12. {
  13. roast::thread a(CHoge(10));
  14. a.join();
  15. }

また、同様のstartメソッドによる起動や、引数指定も可能です。

  1. #include "roast/thread.hpp"
  2. class CHoge
  3. {
  4. public:
  5. int m_a;
  6. CHoge(int a){ m_a = a; }
  7. int operator()(int b)
  8. {
  9. return printf("%d + %d = %d\n", m_a, b, m_a + b);
  10. }
  11. };
  12. void main( void )
  13. {
  14. roast::thread a;
  15. a.start(CHoge(10),20);
  16. a.join();
  17. }

コンストラクタ、及びstartメソッドの第一引数として渡された関数オブジェクトは コピーコンストラクタにより内部的にコピーされたものが使用されます。

このため、パフォーマンスの問題や、コピーコンストラクタによりコピーされた場合正常に動作しない、 ないし処理中や処理結果の関数オブジェクトインスタンスを使用したい場合等の場合には、 予め変数を宣言し、そのポインタを指定する事により、インスタンスのコピーを行わず、 直接指定ポインタのインスタンスを使用させる事が可能です。

  1. #include "roast/thread.hpp"
  2. class CHoge
  3. {
  4. public:
  5. int m_a;
  6. int m_result;
  7. CHoge(int a){ m_a = a; }
  8. int operator()(int b)
  9. {
  10. m_result = m_a + b;
  11. }
  12. };
  13. void main( void )
  14. {
  15. CHoge hoge(10);
  16. roast::thread a(&hoge,20);
  17. a.join();
  18. printf("Result: %d", hoge.m_result);
  19. }

コンストラクタからの例外送出

startメソッドは復帰値型boolになっており、スレッド作成失敗時にはfalseを復帰する。 しかしコンストラクタは復帰値を持てないため、スレッド作成失敗時には thread_exception クラスによる例外を送出するようになっている。