Lang/C++/C++11/thread
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
#topicpath
/////////////////////////////////////////////////////////...
* 目次 [#z44d9e2e]
#contents();
/////////////////////////////////////////////////////////...
* 初めに [#s8cb5470]
- C++11 では thread がサポートされている。→ std::thread c...
- gcc では build 時に -pthread オプションを要求される場合...
/////////////////////////////////////////////////////////...
* std::thread [#std-thread]
- C++11 では、 std::thread class を用いてスレッドの生成と...
- std::thread は、 ''copy 不可・move 不可'' となっている。
/////////////////////////////////////////////////////////...
* thread の作成 [#create-thread]
- 関数 foo(), bar() をそれぞれ別の thread で実行する
// 排他出力処理
mutex print_mutex;
void print( const string &s ) {
lock_guard<mutex> lk(print_mutex);
cout << s << endl;
}
void foo() {
print( "foo" );
}
void bar() {
print( "bar" );
}
// foo(), bar() をそれぞれ別の thread で実行
thread th1{ foo };
thread th2{ bar };
th1.join();
th2.join();
//=======================================================...
** 引数付き関数を別 thread で実行する [#bc57c0ea]
- 書式
std::thread object_name{ <thread-func>, <thread-func-arg...
- 関数や関数オブジェクトの呼び出し演算子が仮引数を取る場...
- std::thread のコンストラクタに渡された実引数は、受け取...
-- 上記コピーを避けたい場合は、実引数をムーブするか、 std...
-- std::ref() を使用した場合、作成した thread に参照が渡...
- thread 内で例外が発生し、 catch されないまま thread 外...
- 例
void foo(int id) {
print( "foo: %d", id );
}
int foo_arg = 20;
std::thread th1{ foo, foo_arg };
//=======================================================...
** クラスメンバ関数をスレッド関数にする場合 [#vf4bce69]
- class member な関数は、そのままではスレッド関数に指定出...
class ClsA {
public:
ClsA() {}
virtual ~ClsA() {}
void Init();
...
void ThreadMain();
private:
std::thread::id m_thread_id_main;
...
};
~
// スレッドの開始
void ClsA::Init()
{
// スレッド生成時に this を渡してやる
std::thread main_thread( &ClsA::ThreadMain, this );
m_thread_id_main = main_thread.get_id();
// detach する。
main_thread.detach();
....
}
/////////////////////////////////////////////////////////...
* thread 終了を待機する [#join]
- thread の終了を待機するところで std::thread::join() を...
std::thread th1( foo() );
th1.join();
cout << "th1 is joined" << endl;
- join() 呼び出しが完了するまで、 join() の実行元スレッド...
- join() の呼び出しが完了すると、そのオブジェクト(上記例...
- 既に join() の呼び出しが完了しているオブジェクトに対し...
- std::thread::joinable() の返り値を見ることによって、そ...
- join() 呼び出し可能なオブジェクトが破棄される場合、 std...
- join() 可能なオブジェクトは、破棄される前に必ず join() ...
/////////////////////////////////////////////////////////...
* thread 終了を待機可能かどうか判定する [#vd818d20]
- std::thread::joinable() はスレッドの終了を待機可能かど...
bool std::thread::joinable() const;
/////////////////////////////////////////////////////////...
* thread を手放す [#t3ea7895]
- void srd::thread::detach() を実行する
using namespace std;
void foo() {
// 時間の掛かる処理
...
}
void bar() {
thread th1( foo() );
th1.detach(); // スレッドを手放す
}
// 関数 bar() が終了しても、スレッド foo() は別スレッド...
- std::thread::detach() が呼び出されると、そのオブジェク...
- 既に detach() が呼び出されたオブジェクトに対して detach...
- std::exit() が呼ばれると、実行中のスレッドがあってもプ...
/////////////////////////////////////////////////////////...
* thread の識別 [#x6a39824]
- std::thread::id std::thread::get_id() を呼ぶ
void foo( ostringstream &os ) {
os << "foo(): " << this_thread::get_id() << endl;
}
void bar( ostringstream &os ) {
os << "bar(): " << this_thread::get_id() << endl;
}
ostringstream os_foo;
ostringstream os_bar;
thread th1( foo(), ref( os_foo ) );
thread th2( bar(), ref( os_bar ) );
// それぞれの thread ID を得る
thread::id id1 = th1.get_id();
thread::id id2 = th2.get_id();
thread::id id3 = this_thread::get_id();
assert( id1 != is2 );
assert( id1 != is3 );
assert( id2 != is3 );
th1.join();
th2.join();
cout << os_foo.str();
cout << os_bar.str();
cout << "main thread : " << this_thread::get_id() << endl;
- std::thread::id は文字列型なので、無効な値(実行中でな...
thread::id of a non-executing thread
- std::thread::id は、std::thread が管理する一意な ID
- 実行が終了したスレッドの std::thread::id は、再利用され...
/////////////////////////////////////////////////////////...
* 現在の thread の処理を明け渡す [#s20f6dff]
void std::this_thread::yield() noexcept;
- この関数は、プロセッサを専有し続けることなく、適宜他の...
- OS が CPU を管理しない(=ノンエンプリエンティブな)環...
/////////////////////////////////////////////////////////...
* 現在の thread をスリープする [#q1284bbf]
namespace std {
namespace this_thread {
template <class Clock, class Duration>
void sleep_until( const chrono::time_point<Clock...
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Perio...
}
}
- この関数を使用することで、現在実行しているスレッドの処...
-- sleep_until() 実引数で渡した自国まで処理を中断する。
-- sleep_for() 実引数で渡した時間だけ処理を中断する。
/////////////////////////////////////////////////////////...
* 並行実行できる thread の数を取得する [#te2d6f95]
namespace std {
class thread {
public:
static unsigned int hardware_concurrency() noexc...
};
}
- この関数は、現在実行している環境で並行実行出来るスレッ...
- この関数によって返される値はあくまで参考値であり、実際...
- 並行実行出来るスレッド数を計算できない場合や、実装によ...
/////////////////////////////////////////////////////////...
* mutex [#mutex]
namespace std {
class mutex {
public:
void lock();
bool try_lock();
void unlock();
};
class recursive_mutex {
public:
void lock();
bool try_lock();
void unlock();
};
}
- lock()
-- オブジェクトに対しロックを掛ける
-- 呼び出した時点で、同じオブジェクトに対し既にロックがか...
- try_lock():
-- ロックを試行する
|~状態 |~try_loclk() 呼び出し結果 |~備考 |
|どのスレッドもそのオブジェクトにロックをかけていない時 |...
|他のスレッドから既にロックがかけられている場合 |ロックに...
- unlock()
-- オブジェクトに掛けたロックを解除する
//=======================================================...
** std::mutex [#std-mutex]
- 再帰的にロックは掛けられない →1スレッド内で同じオブジェ...
- デッドロックにはまった場合、実装系がデッドロックを発見...
//=======================================================...
** std::recursive_mutex [#recursive_mutex]
- 再帰的にロック出来る mutex
- スレッド間で排他的だが、同一スレッド内からは同一オブジ...
-- ロックしたのと同じ回数アンロックすると、ロックが解除さ...
- 何回までロックを掛けられるかは規定がない。上限を超えた...
-- try_lock(): false が返る
-- lock() : std::system_error 例外を送出
//=======================================================...
** std::timed_mutex [#timed_mutex]
- タイムアウト付き mutex
- lock() / try_lock() も使用出来る
- タイムアウト指定出来るロック関数が用意されている
-- try_lock_for() : 指定時間だけロックを試行する
-- try_lock_until() : 指定時刻までロックを試行する
-- タイムアウト付きロック関数は、タイムアウトまでにロック...
//=======================================================...
** std::timed_recursive_mutex [#timed_recursive_mutex]
- 再帰的にロックを掛けられる、タイムアウト付き mutex
- std::recursivemutex, std::timed_mutex の両方の機能を備...
//=======================================================...
** std::shared_mutex [C++17] [#shared_timed_mutex]
//=======================================================...
** std::shared_timed_mutex [C++14] [#shared_timed_mutex]
/////////////////////////////////////////////////////////...
* リソースのロックを管理する [#o619d861]
//=======================================================...
** std::lock_guard [#lock_guard]
- ロックのインスタンスを生成し、それが有効な間をロックの...
- よって、明示的なロック解除の I/F は使わない
#include <mutex>
{
std::mutex mtx;
{
std::lock_guard<mutex> lk( mtx ); // ここから...
// 処理...
} // lk の有効なスコープを抜け、lk のインスタンスが...
}
//=======================================================...
** std::unique_lock [#unique_lock]
- コンストラクタ第2引数に std::defer_lock 変数を渡すと、...
- 後からロックを取得するには、 lock() / try_lock() を呼び...
- 使用する mutex が try_lock_for(), try_lock_until() メン...
- コンストラクタに std::defer_lock が渡され、ロックを取得...
- release() : 管理しているオブジェクトを手放す
- unlock() : 任意のタイミングでロックを解除する
- owns_lock() : 現在ロックを取得しているかどうかを確認出...
/////////////////////////////////////////////////////////...
* 複数のリソースをロックする [#w31f69a0]
/////////////////////////////////////////////////////////...
* ロックせずに排他アクセスする [#j61ebc0e]
//=======================================================...
** std::memory_order [#e66f6277]
//=======================================================...
** std::atomic [#qf70be40]
/////////////////////////////////////////////////////////...
* スレッドセーフに1度だけ関数を呼び出す [#g8f42eac]
/////////////////////////////////////////////////////////...
* 条件変数を使用する [#kb3e1964]
/////////////////////////////////////////////////////////...
* thread をまたいで値や例外を受け渡す [#std-promise-future]
- スレッド間で非同期に値や例外を受け渡す方法として、 std:...
//=======================================================...
** 使い方 [#std-promise-future-usage]
+ std::promise の実体生成し下記を呼び、その実体に対応する...
get_future()
+ 値と例外は、以下のいずれかを用いてどちらか一つを、''1回...
set_value()
set_exception()
-- 値または例外が既に設定された状態で再度これらが呼び出さ...
-- 対応する std::future が値や例外を受け取るタイミングを...
set_value_at_thread_exit()
set_exception_at_thread_exit()
+ std::promise の get_future() で取得した std::future の ...
-- 設定されたのが値ではなく例外だった場合は、例外が送出さ...
-- まだ std::promise で値も例外も設定されていなかった場合...
--- wait() は、値または例外の設定を待機するもので、設定さ...
-- 値の設定待ちに条件を付けたい場合は、以下を使用する
wait_for( std::chrono::duration d ) // 指定した時...
wait_until( std::chrono::time_point tp ) // 指定した時...
これらの返り値は以下
std:future_status::ready // 指定時間内に値か例外が設...
std:future_status::timeout // 値も例外も設定されないま...
std:future_status::deferred // 実行のタイミングが延期さ...
- ''std::future の get() を呼び出すと、 std::promise との...
//=======================================================...
** 使い方の例 [#std-promise-future-example]
- 以下は、 std::string をやり取りする例:
#include <iostream>
#include <thread>
#include<future>
static std::mutex g_print_mutex;
void LockPrintf( const std::string & str )
{
std::lock_guard<std::mutex> lk( g_print_mutex );
std::cout << str << std::endl;
}
void ThreadFuncA( std::promise<std::string> pr )
{
std::string sendstr ="from ThreadFuncA";
pr.set_value( sendstr ); // 他のスレッドに受け渡...
LockPrintf( "ThreadFuncA" );
}
int main( int argc, char * argv[] )
{
std::promise<std::string> prom;
std::future<std::string> futu = prom.get_future(); /...
std::thread th_a( ThreadFuncA, move( prom ) );
std::string future_string = "Rcv from A: " + futu.get();
LockPrintf( future_string );
th_a.join();
return( 0 );
}
/////////////////////////////////////////////////////////...
* 非同期処理をする [#kd28f4df]
/////////////////////////////////////////////////////////...
* スレッドローカル変数を使用する [#k24f952f]
終了行:
#topicpath
/////////////////////////////////////////////////////////...
* 目次 [#z44d9e2e]
#contents();
/////////////////////////////////////////////////////////...
* 初めに [#s8cb5470]
- C++11 では thread がサポートされている。→ std::thread c...
- gcc では build 時に -pthread オプションを要求される場合...
/////////////////////////////////////////////////////////...
* std::thread [#std-thread]
- C++11 では、 std::thread class を用いてスレッドの生成と...
- std::thread は、 ''copy 不可・move 不可'' となっている。
/////////////////////////////////////////////////////////...
* thread の作成 [#create-thread]
- 関数 foo(), bar() をそれぞれ別の thread で実行する
// 排他出力処理
mutex print_mutex;
void print( const string &s ) {
lock_guard<mutex> lk(print_mutex);
cout << s << endl;
}
void foo() {
print( "foo" );
}
void bar() {
print( "bar" );
}
// foo(), bar() をそれぞれ別の thread で実行
thread th1{ foo };
thread th2{ bar };
th1.join();
th2.join();
//=======================================================...
** 引数付き関数を別 thread で実行する [#bc57c0ea]
- 書式
std::thread object_name{ <thread-func>, <thread-func-arg...
- 関数や関数オブジェクトの呼び出し演算子が仮引数を取る場...
- std::thread のコンストラクタに渡された実引数は、受け取...
-- 上記コピーを避けたい場合は、実引数をムーブするか、 std...
-- std::ref() を使用した場合、作成した thread に参照が渡...
- thread 内で例外が発生し、 catch されないまま thread 外...
- 例
void foo(int id) {
print( "foo: %d", id );
}
int foo_arg = 20;
std::thread th1{ foo, foo_arg };
//=======================================================...
** クラスメンバ関数をスレッド関数にする場合 [#vf4bce69]
- class member な関数は、そのままではスレッド関数に指定出...
class ClsA {
public:
ClsA() {}
virtual ~ClsA() {}
void Init();
...
void ThreadMain();
private:
std::thread::id m_thread_id_main;
...
};
~
// スレッドの開始
void ClsA::Init()
{
// スレッド生成時に this を渡してやる
std::thread main_thread( &ClsA::ThreadMain, this );
m_thread_id_main = main_thread.get_id();
// detach する。
main_thread.detach();
....
}
/////////////////////////////////////////////////////////...
* thread 終了を待機する [#join]
- thread の終了を待機するところで std::thread::join() を...
std::thread th1( foo() );
th1.join();
cout << "th1 is joined" << endl;
- join() 呼び出しが完了するまで、 join() の実行元スレッド...
- join() の呼び出しが完了すると、そのオブジェクト(上記例...
- 既に join() の呼び出しが完了しているオブジェクトに対し...
- std::thread::joinable() の返り値を見ることによって、そ...
- join() 呼び出し可能なオブジェクトが破棄される場合、 std...
- join() 可能なオブジェクトは、破棄される前に必ず join() ...
/////////////////////////////////////////////////////////...
* thread 終了を待機可能かどうか判定する [#vd818d20]
- std::thread::joinable() はスレッドの終了を待機可能かど...
bool std::thread::joinable() const;
/////////////////////////////////////////////////////////...
* thread を手放す [#t3ea7895]
- void srd::thread::detach() を実行する
using namespace std;
void foo() {
// 時間の掛かる処理
...
}
void bar() {
thread th1( foo() );
th1.detach(); // スレッドを手放す
}
// 関数 bar() が終了しても、スレッド foo() は別スレッド...
- std::thread::detach() が呼び出されると、そのオブジェク...
- 既に detach() が呼び出されたオブジェクトに対して detach...
- std::exit() が呼ばれると、実行中のスレッドがあってもプ...
/////////////////////////////////////////////////////////...
* thread の識別 [#x6a39824]
- std::thread::id std::thread::get_id() を呼ぶ
void foo( ostringstream &os ) {
os << "foo(): " << this_thread::get_id() << endl;
}
void bar( ostringstream &os ) {
os << "bar(): " << this_thread::get_id() << endl;
}
ostringstream os_foo;
ostringstream os_bar;
thread th1( foo(), ref( os_foo ) );
thread th2( bar(), ref( os_bar ) );
// それぞれの thread ID を得る
thread::id id1 = th1.get_id();
thread::id id2 = th2.get_id();
thread::id id3 = this_thread::get_id();
assert( id1 != is2 );
assert( id1 != is3 );
assert( id2 != is3 );
th1.join();
th2.join();
cout << os_foo.str();
cout << os_bar.str();
cout << "main thread : " << this_thread::get_id() << endl;
- std::thread::id は文字列型なので、無効な値(実行中でな...
thread::id of a non-executing thread
- std::thread::id は、std::thread が管理する一意な ID
- 実行が終了したスレッドの std::thread::id は、再利用され...
/////////////////////////////////////////////////////////...
* 現在の thread の処理を明け渡す [#s20f6dff]
void std::this_thread::yield() noexcept;
- この関数は、プロセッサを専有し続けることなく、適宜他の...
- OS が CPU を管理しない(=ノンエンプリエンティブな)環...
/////////////////////////////////////////////////////////...
* 現在の thread をスリープする [#q1284bbf]
namespace std {
namespace this_thread {
template <class Clock, class Duration>
void sleep_until( const chrono::time_point<Clock...
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Perio...
}
}
- この関数を使用することで、現在実行しているスレッドの処...
-- sleep_until() 実引数で渡した自国まで処理を中断する。
-- sleep_for() 実引数で渡した時間だけ処理を中断する。
/////////////////////////////////////////////////////////...
* 並行実行できる thread の数を取得する [#te2d6f95]
namespace std {
class thread {
public:
static unsigned int hardware_concurrency() noexc...
};
}
- この関数は、現在実行している環境で並行実行出来るスレッ...
- この関数によって返される値はあくまで参考値であり、実際...
- 並行実行出来るスレッド数を計算できない場合や、実装によ...
/////////////////////////////////////////////////////////...
* mutex [#mutex]
namespace std {
class mutex {
public:
void lock();
bool try_lock();
void unlock();
};
class recursive_mutex {
public:
void lock();
bool try_lock();
void unlock();
};
}
- lock()
-- オブジェクトに対しロックを掛ける
-- 呼び出した時点で、同じオブジェクトに対し既にロックがか...
- try_lock():
-- ロックを試行する
|~状態 |~try_loclk() 呼び出し結果 |~備考 |
|どのスレッドもそのオブジェクトにロックをかけていない時 |...
|他のスレッドから既にロックがかけられている場合 |ロックに...
- unlock()
-- オブジェクトに掛けたロックを解除する
//=======================================================...
** std::mutex [#std-mutex]
- 再帰的にロックは掛けられない →1スレッド内で同じオブジェ...
- デッドロックにはまった場合、実装系がデッドロックを発見...
//=======================================================...
** std::recursive_mutex [#recursive_mutex]
- 再帰的にロック出来る mutex
- スレッド間で排他的だが、同一スレッド内からは同一オブジ...
-- ロックしたのと同じ回数アンロックすると、ロックが解除さ...
- 何回までロックを掛けられるかは規定がない。上限を超えた...
-- try_lock(): false が返る
-- lock() : std::system_error 例外を送出
//=======================================================...
** std::timed_mutex [#timed_mutex]
- タイムアウト付き mutex
- lock() / try_lock() も使用出来る
- タイムアウト指定出来るロック関数が用意されている
-- try_lock_for() : 指定時間だけロックを試行する
-- try_lock_until() : 指定時刻までロックを試行する
-- タイムアウト付きロック関数は、タイムアウトまでにロック...
//=======================================================...
** std::timed_recursive_mutex [#timed_recursive_mutex]
- 再帰的にロックを掛けられる、タイムアウト付き mutex
- std::recursivemutex, std::timed_mutex の両方の機能を備...
//=======================================================...
** std::shared_mutex [C++17] [#shared_timed_mutex]
//=======================================================...
** std::shared_timed_mutex [C++14] [#shared_timed_mutex]
/////////////////////////////////////////////////////////...
* リソースのロックを管理する [#o619d861]
//=======================================================...
** std::lock_guard [#lock_guard]
- ロックのインスタンスを生成し、それが有効な間をロックの...
- よって、明示的なロック解除の I/F は使わない
#include <mutex>
{
std::mutex mtx;
{
std::lock_guard<mutex> lk( mtx ); // ここから...
// 処理...
} // lk の有効なスコープを抜け、lk のインスタンスが...
}
//=======================================================...
** std::unique_lock [#unique_lock]
- コンストラクタ第2引数に std::defer_lock 変数を渡すと、...
- 後からロックを取得するには、 lock() / try_lock() を呼び...
- 使用する mutex が try_lock_for(), try_lock_until() メン...
- コンストラクタに std::defer_lock が渡され、ロックを取得...
- release() : 管理しているオブジェクトを手放す
- unlock() : 任意のタイミングでロックを解除する
- owns_lock() : 現在ロックを取得しているかどうかを確認出...
/////////////////////////////////////////////////////////...
* 複数のリソースをロックする [#w31f69a0]
/////////////////////////////////////////////////////////...
* ロックせずに排他アクセスする [#j61ebc0e]
//=======================================================...
** std::memory_order [#e66f6277]
//=======================================================...
** std::atomic [#qf70be40]
/////////////////////////////////////////////////////////...
* スレッドセーフに1度だけ関数を呼び出す [#g8f42eac]
/////////////////////////////////////////////////////////...
* 条件変数を使用する [#kb3e1964]
/////////////////////////////////////////////////////////...
* thread をまたいで値や例外を受け渡す [#std-promise-future]
- スレッド間で非同期に値や例外を受け渡す方法として、 std:...
//=======================================================...
** 使い方 [#std-promise-future-usage]
+ std::promise の実体生成し下記を呼び、その実体に対応する...
get_future()
+ 値と例外は、以下のいずれかを用いてどちらか一つを、''1回...
set_value()
set_exception()
-- 値または例外が既に設定された状態で再度これらが呼び出さ...
-- 対応する std::future が値や例外を受け取るタイミングを...
set_value_at_thread_exit()
set_exception_at_thread_exit()
+ std::promise の get_future() で取得した std::future の ...
-- 設定されたのが値ではなく例外だった場合は、例外が送出さ...
-- まだ std::promise で値も例外も設定されていなかった場合...
--- wait() は、値または例外の設定を待機するもので、設定さ...
-- 値の設定待ちに条件を付けたい場合は、以下を使用する
wait_for( std::chrono::duration d ) // 指定した時...
wait_until( std::chrono::time_point tp ) // 指定した時...
これらの返り値は以下
std:future_status::ready // 指定時間内に値か例外が設...
std:future_status::timeout // 値も例外も設定されないま...
std:future_status::deferred // 実行のタイミングが延期さ...
- ''std::future の get() を呼び出すと、 std::promise との...
//=======================================================...
** 使い方の例 [#std-promise-future-example]
- 以下は、 std::string をやり取りする例:
#include <iostream>
#include <thread>
#include<future>
static std::mutex g_print_mutex;
void LockPrintf( const std::string & str )
{
std::lock_guard<std::mutex> lk( g_print_mutex );
std::cout << str << std::endl;
}
void ThreadFuncA( std::promise<std::string> pr )
{
std::string sendstr ="from ThreadFuncA";
pr.set_value( sendstr ); // 他のスレッドに受け渡...
LockPrintf( "ThreadFuncA" );
}
int main( int argc, char * argv[] )
{
std::promise<std::string> prom;
std::future<std::string> futu = prom.get_future(); /...
std::thread th_a( ThreadFuncA, move( prom ) );
std::string future_string = "Rcv from A: " + futu.get();
LockPrintf( future_string );
th_a.join();
return( 0 );
}
/////////////////////////////////////////////////////////...
* 非同期処理をする [#kd28f4df]
/////////////////////////////////////////////////////////...
* スレッドローカル変数を使用する [#k24f952f]
ページ名: