【C++同時およびマルチスレッド】3_スレッド伝達パラメータ詳細、detach注意事項
9444 ワード
スレッドidの取得 std::this_thread::get_id()
出力:
スレッド呼び出しオブジェクトのパラメータ転送
パラメータとして参照
参照がパラメータとして使用されると、参照伝達ではなくパラメータコピーが発生します.
C++自体に引用(&)がありますが、なぜstd::refを導入したのでしょうか.は主に関数式プログラミング(例えばstd::thread,std::bind)が使用される場合、参照ではなくパラメータを直接コピーすることを考慮する. std::thread,std::bind既存のテンプレートに基づいて関数を生成するのが原理ですが、std::thread,std::bindは生成した関数が実行されるときに伝達されるパラメータが有効かどうか分かりません.したがって、リファレンス伝達ではなくパラメータ伝達を選択します.リファレンス伝達の場合、std::refとstd::crefが役に立ちます.
出力:
補足証明:注意クラス内コピー構造関数印刷
出力:
パラメータとしてポインタ
ポインタがパラメータである場合、パラメータは実パラメータと同じアドレスを指す.
出力:【実パラメータ、形パラメータが同じアドレスを指す】
パラメータとして暗黙的に変換されたオブジェクト
パラメータとして暗黙的変換が発生する可能性のあるオブジェクトを使用する場合、暗黙的タイプ変換は避けるべきであり、呼び出しスレッドが
出力:
パラメータとしてスマートポインタを使用する
出力:
まとめベースデータ型がパラメータである場合、参照ではなく値伝達を推奨します. カスタムデータ型をパラメータとして使用する場合は、暗黙的なタイプ変換は避けてください.呼び出しスレッドで一時オブジェクトをアクティブに生成し、サブスレッドでリファレンス受信を使用する方法です. detachではなくjoinをできるだけ使用します(簡単であればあるほど信頼できます).
#include
#include
using namespace std;
std::thread::id main_thread_id = std::this_thread::get_id(); // !!!
void is_main_thread()
{
cout << std::this_thread::get_id() << endl; // !!
if (main_thread_id == std::this_thread::get_id()) // !!
cout << "This is the main thread" << endl;
else
cout << "This is not main thread" << endl;
}
int main()
{
is_main_thread();
thread th(is_main_thread);
th.join();
return 0;
}
出力:
1
This is the main thread
2
This is not main thread
スレッド呼び出しオブジェクトのパラメータ転送
パラメータとして参照
参照がパラメータとして使用されると、参照伝達ではなくパラメータコピーが発生します.
std::ref() thread::detach()
を同時に使用する場合、プライマリ・スレッドのローカル属性リソース(オブジェクト)がスレッドによって使用され、プライマリ・スレッドがサブスレッドより先に終了するかどうかを考慮する必要があります. thread::detach() , std::ref() 。
, , , , , 。
C++自体に引用(&)がありますが、なぜstd::refを導入したのでしょうか.
#include
#include
using namespace std;
void thread_func(const int &i)
{
cout << "thread_func begin" << endl;
cout << "i = " << i << endl;
const_cast(i) = i * 2;
cout << "i = " << i << endl;
for (int i=0; i<1000; ++i)
{ }
// obj.i ...
cout << "thread_func end" << endl;
}
int main()
{
cout << "main begin" << endl;
int i1 = 10;
cout << i1 << endl;
thread th1(thread_func, i1); // i1 !!!
th1.join();
// th1.detach(); // i1 ,
cout << i1 << endl;
cout << "=================" << endl;
int i2 = 10;
cout << i2 << endl;
thread th2(thread_func, std::ref(i2)); // std::ref(i2) !!!
th2.join();
// th2.detach(); // , i2 , , !
cout << i2 << endl;
cout << "main end" << endl;
return 0;
}
出力:
main begin
10
thread_func begin
i = 10
i = 20
thread_func end
10 // !!!
=================
10
thread_func begin
i = 10
i = 20
thread_func end
20 // !!!
main end
補足証明:注意クラス内コピー構造関数印刷
#include
#include
using namespace std;
class Base {
public:
Base(int i = 0) : m_i(i)
{
cout << "Base(int i) " << m_i << endl;
}
Base(const Base &obj) : m_i(obj.m_i)
{
cout << "Base(const Base &obj) " << m_i << endl;
}
~Base()
{
cout << "~Base() " << m_i << endl;
}
public:
int m_i;
};
void thread_func(const Base &obj)
{
cout << "thread_func begin" << endl;
cout << obj.m_i << endl;
for (int i=0; i<1000; ++i)
{ }
// obj.m_i ...
cout << "thread_func end" << endl;
}
int main()
{
cout << "main begin" << endl;
Base obj1{1};
Base obj2{2};
cout << "=================" << endl;
thread th1(thread_func, obj1); // obj1 !!!
th1.join();
// th1.detach(); // obj1 ,
cout << "=================" << endl;
thread th2(thread_func, std::ref(obj2)); // std::ref(obj2) !!!
th2.join();
// th2.detach(); // , obj2 , , !
cout << "=================" << endl;
cout << "main end" << endl;
return 0;
}
出力:
main begin
Base(int i) 1
Base(int i) 2
================= // , !!!
Base(const Base &obj) 1 // ( )
Base(const Base &obj) 1
~Base() 1
thread_func begin
1
thread_func end
~Base() 1
================= // , !!!
thread_func begin
2
thread_func end
=================
main end
~Base() 2
~Base() 1
パラメータとしてポインタ
ポインタがパラメータである場合、パラメータは実パラメータと同じアドレスを指す.
thread::detach()
を同時に使用する場合、プライマリ・スレッドのローカル属性リソース(オブジェクト)がスレッドによって使用され、プライマリ・スレッドがサブスレッドより先に終了するかどうかを考慮する必要があります. thread::detach() , , 。
, , , , , 。
#include
#include
using namespace std;
void thread_func(const char *pt)
{
cout << "thread_func begin " << pt[0] << endl;
cout << "pt addr : " << static_cast(pt) << endl;
for (int i=0; i<1000; ++i)
{ }
// pt ...
cout << "thread_func end" << endl;
}
int main()
{
cout << "main begin" << endl;
const char *pt1 = "1"; //
const char *pt2 = new char('2'); //
thread th1(thread_func, pt1);
th1.join();
// th1.detach(); // 、 ,
thread th2(thread_func, pt2);
th2.join();
// th2.detach(); // 、 ,
cout << "pt1 addr : " << static_cast(pt1) << endl;
cout << "pt2 addr : " << static_cast(pt2) << endl;
delete pt2;
cout << "main end" << endl;
return 0;
}
出力:【実パラメータ、形パラメータが同じアドレスを指す】
main begin
thread_func begin 1
pt addr : 0x405043 // A
thread_func end
thread_func begin 2
pt addr : 0xf617f0 // B
thread_func end
pt1 addr : 0x405043 // A'
pt2 addr : 0xf617f0 // B'
main end
パラメータとして暗黙的に変換されたオブジェクト
パラメータとして暗黙的変換が発生する可能性のあるオブジェクトを使用する場合、暗黙的タイプ変換は避けるべきであり、呼び出しスレッドが
thread::detach()
をアクティブに生成して同時に使用する場合、メインスレッド内のローカル属性リソース(オブジェクト)がスレッドによって使用され、メインスレッドがサブスレッドより先に終了するかどうかを考慮する必要がある. , 。
, , , , , 。
#include
#include
using namespace std;
class Base {
public:
Base(int i = 0) : m_i(i)
{
cout << "Base(int i) " << std::this_thread::get_id() << endl;
}
Base(const Base &obj) : m_i(obj.m_i)
{
cout << "Base(const Base &obj) " << std::this_thread::get_id() << endl;
}
~Base()
{
cout << "~Base() " << std::this_thread::get_id() << endl;
}
public:
int m_i;
};
void thread_func(const Base &)
{ }
int main()
{
cout << "main begin" << endl;
cout << "main thread id " << std::this_thread::get_id() << endl;
int i = 10;
thread th1(thread_func, i);
th1.join();
// th2.detach(); // , , !!!
cout << "=================" << endl;
thread th2(thread_func, Base(i)); // , Base(i) !!!
th2.join();
cout << "main end" << endl;
return 0;
}
出力:
main begin
main thread id 1
Base(int i) 2 // , !!!
~Base() 2
=================
Base(int i) 1
Base(const Base &obj) 1 // , ( ) , !!!
Base(const Base &obj) 1
~Base() 1
~Base() 1
~Base() 3
main end
パラメータとしてスマートポインタを使用する
#include
#include
#include
using namespace std;
void thread_func(unique_ptr pt)
{
cout << "thread_func begin" << endl;
cout << *pt << endl;
cout << "thread_func end" << endl;
}
int main()
{
cout << "main begin" << endl;
unique_ptr up{new int(1)};
thread th(thread_func, std::move(up));
th.join();
cout << "main end" << endl;
return 0;
}
出力:
main begin
thread_func begin
1
thread_func end
main end
まとめ