質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

6914閲覧

std::thread と Windows API

BeatStar

総合スコア4958

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/05/30 04:34

編集2017/06/05 03:38

C/C++でやっています。

比較的最新? のMinGW を再インストールして C++11 の std::thread を使おうとしています。

本家の MinGW ( minimal? でない方 ) をインストールするときは "posix" と "win32" の2種類があるようで、

どれがいいかよくわからなかったので CUI,GUIどちらでもいいように両方 ( posix & win32 ) をインストールしました。

C++11 の std::thread を boostjp に相当するサイト ( 名前忘れましたが... ) 等を参考に自分なりにクラス化してみました。

デザインパターンのTemplateMethodパターンを適用して、

IThreadインターフェースクラス を定義。

( 厳密には Javaでいう abstractか。 )

C++

1[ IThread ] 2+ コンストラクタ() 3+ デストラクタ virtual 4+ Begin( void ) : bool 5+ Join( void ) : bool 6+ End( void ) : bool 7- *th : std::thread

としました。

コンストラクタは まだ空ですが。

メンバオブジェクト th は std::thread のポインタとします。

で、ソースコードは

C++

1// IThread インターフェース。TemplateMethodパターン適用。 2class IThread{ 3 public: 4 IThread(); 5 virtual ~IThread(); 6 7 bool Begin( void ); 8 bool Join( void ); 9 bool End( void ); 10 11 virtual void Execute( void ) = 0; 12 private: 13 std::thread *th; 14}; 15 16 17 18/************************************************************** 19* 20* クラス名: IThread 21* 22* 種 類: コンストラクタ 23* 24* 目 的: マルチスレッド操作 25* 26* 引 数: 27* 28* 参 ・ 引: 29* 30* 31* 備 考: 32* 33* 34**************************************************************/ 35 36IThread::IThread(){ 37 38} 39 40 41 42/************************************************************** 43* 44* クラス名: IThread 45* 46* 種 類: デストラクタ 47* 48* 目 的: マルチスレッド操作 49* 50* 引 数: 51* 52* 参 ・ 引: 53* 54* 55* 備 考: 56* 57* 58**************************************************************/ 59 60IThread::~IThread(){ 61 delete th; 62} 63 64 65 66/************************************************************** 67* 68* クラス名: CThread 69* 70* 関 数 名: Begin 71* 72* 目 的: スレッドを生成し、開始する 73* 74* 引 数: 75* LPVOID arg := スレッド用引数 76* 77* 戻 り 値: 78* bool 79* 80* 使 用 例: 81* if( CThread.Begin( &arg ) == true )... 82* 83* 参 ・ 引: 84* 85* 86* 備 考: 87* 88* 89**************************************************************/ 90 91bool IThread::Begin( void ){ 92 try{ 93 th = new thread( &IThread::Execute, this ); 94 return true; 95 }catch( system_error e ){ 96 return false; // スレッド作成のためのリソース不足 or システム・プロセスが規定するスレッド数の上限を超えている 97 } 98} 99 100 101 102/************************************************************** 103* 104* クラス名: CThread 105* 106* 関 数 名: Join 107* 108* 目 的: スレッドが終了するまで待機させる 109* 110* 引 数: 111* void 112* 113* 戻 り 値: 114* bool 115* 116* 使 用 例: 117* if( CThread.Join() == true )... 118* 119* 参 ・ 引: 120* 121* 122* 備 考: 123* 124* 125**************************************************************/ 126 127bool IThread::Join( void ){ 128 try{ 129 th->join(); 130 return true; 131 }catch( system_error e ){ 132 return false; 133 } 134} 135 136 137 138/************************************************************** 139* 140* クラス名: CThread 141* 142* 関 数 名: End 143* 144* 目 的: スレッドを終了させる 145* 146* 引 数: 147* void 148* 149* 戻 り 値: 150* bool 151* 152* 使 用 例: 153* if( CThread.End() == true )... 154* 155* 参 ・ 引: 156* 157* 158* 備 考: 159* 160* 161**************************************************************/ 162 163bool IThread::End( void ){ 164 try{ 165 th->detach(); 166 return true; 167 }catch( system_error e ){ 168 return false; 169 } 170}

のようにしています。

これを継承して、たとえば CThread1クラスを定義します。

C++

1class CThread : public IThread{ 2 public: 3 CThread( int id ) : m_id(id){} 4 5 // 実装。 6 void Execute( void ){ 7 // ここで int m_id を表示 8 9 for( int i = 0; i < 100; i++ ){ 10 // cout か MessageBoxかなんかで int i のデータを出力... 11 } 12 } 13 private: 14 int m_id; 15};

みたいに 継承先で 実際に行う処理を記述します。

IThread::Executeは 実際に定義してもいいですが、aファイルにしているので、

固定してしまうと 使えないです。

なので IThread を継承して Executeメンバ関数を実装して...

とやろうとしています。

ここまではいいです。

でposix版でやると普通にうまくいきます。( コンパイルも通りますし、実行結果もtrue。 )

ただ、Windows API も実装して GUIタイプ ( "-mwindows" をつけてやる方 ) でやると

なぜかクラッシュします。

趣味でやっているので あまり詳しくないですが posix は CUI のようらしいので、

GUIで動けるように win32版でコンパイルしました。

すると、次はコンパイルそのものが通りません。

エラー: 'thread' というものは 名前空間 'std' に存在しません エラー: 'th' というものは このスコープでは未定義です ... ( 大体同じようなメッセージ )

と出ます。 ( コンパイラ g++ のパスも間違っていないようですし。 )

posix の方に切り替えると 普通に出来ます。

なぜなのでしょうか?

また解決方法も教えていただきたいです。

[情報]
言語 : C/C++
コンパイラ : MinGW ( minimal でない方 )
バージョン : posix版, win32版 ともに 6.2.0 ( i686-posix-dwarf-rev1 及び i686-win32-dwarf-rev1 )
やりたいこと: GUI・CUI どちらでも std::thread を使えるようにし、クラッシュしないようにしたい
知りたいこと: "やりたいこと" + 理由と解決方法

宜しくお願い致します。


[追記]

C++

1// Original.cpp 2// 必要なヘッダはインクルードされていて、リンクもされているとして。 3 4 5/* 6class CThread1 : public IThread{ 7 public: 8 CThread1() throw(int){ 9 try{ 10 Console = new CConsole(); 11 }catch( int e ){ 12 throw -1; 13 } 14 } 15 16 ~CThread1(){ 17 delete Console; 18 } 19 20 void Execute( void ){ 21 Console->Write( "C++" ); 22 Console->Wait(); 23 } 24 private: 25 CConsole* Console; 26}; 27 28class CThread2 : public IThread{ 29 public: 30 CThread2() throw(int){ 31 try{ 32 Console = new CConsole(); 33 }catch( int e ){ 34 throw -2; 35 } 36 } 37 38 ~CThread2(){ 39 delete Console; 40 } 41 42 void Execute( void ){ 43 Console->Write( "Java" ); 44 Console->Wait(); 45 } 46 private: 47 CConsole* Console; 48}; 49 50CThread1* thread1; 51CThread2* thread2; 52 53 54void func( void ){ 55 // CConsole* Console; 56 try{ 57 thread1 = new CThread1(); 58 thread2 = new CThread2(); 59 thread1->Execute(); 60 }catch( int e ){ 61 if( e == -1 ) MessageBox( NULL, "例外 (for Thread1) が投げられた", "エラー", MB_OK ); 62 else MessageBox( NULL, "例外 (for Thread2) が投げられた", "エラー", MB_OK ); 63 } 64} 65 66void end(void){ 67 delete thread1; 68 delete thread2; 69}

という感じでやっています。

WM_CREATEのときに func関数を呼び出して、

WM_DESTROYでend関数で破棄。

という感じです。

CConsoleっていうクラスは コンソールを担当する自作クラスで、多分問題ない(これが原因じゃない)と思います。
( 同じGUIでも Boost::threadで動かすと普通に動きましたから。例外は投げられましたが。今回は関係がないかも。 )

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hmmm

2017/05/30 12:21 編集

CThread をどう使っているのかを記載しないとクラッシュ理由は分からないのでは?あとdetachの意味を勘違いしてそうなのが気になります。
BeatStar

2017/06/05 03:40

detach は スレッドが終了するまで待つ...ですよね。今回は複数のメッセージに跨っているので使っていませんが。 あと、追記しました。
guest

回答2

0

こんにちは。

posix の方に切り替えると 普通に出来ます。

なぜなのでしょうか?

単純にwin32スレッド・モデルでは<thread>をサポートしていないだけのようです。

Qt で MinGW-w64 を使用する際に必要になるスレッドモデルと例外機構の選択について
mingw-w64 threads: posix vs win32

元々MinGWはgccですがgcc(libstdc++)がWin32 APIに対応するとは思えないです。また<thread>を丸々Windows用に開発するのもそれなりに大変なのかも知れません。
だから、サポートしていないだけではないかと思います。

また解決方法も教えていただきたいです。

単純にposixを使えば良いと思います。別にGUI開発でposixを使えないという制限は無いはずです。
先にリンクを示したページによるとWindowsにも対応しているQtは、posix版を推奨しているようですし。

速度が気になる場合はWindows APIを直接叩くしか無いかも。(Qtも結局そうやっているようですね。)

どうしてもWin32ネイティブで<thread>を使いたい場合は、Visual C++やC++Builder, Intel C++等を検討してみるしかないと思います。(これらが、Win32ネイディブで<thread>を実装している裏を取ったわけではないです。VC++は流石にWin32ネイティブでしょうけど。)

投稿2017/05/30 05:26

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

threadの使い方がおかしいです。

detachはthreadを停止させるのではなく、threadクラスによる管理を放棄するというような意味。
ですので、停止はせずそのまま動き続ける。

joinもdetachもせずthreadのデストラクタが呼ばれたらstd::terminateされる。
つまり強制終了です。

Console->Wait();
が何やってるか分からないけど
Executeを処理しているスレッドを終了させずにdelete thread1、delete Consoleでdeleteしたあとに
Wait()が動作しているのであれば不正なメモリアクセスをする可能性がある。

ここから直すのであれば、まずjoinしてからdeleteする

c++

1void end(void){ 2 thread1->Join();//joinabbleが使えないのIFなのでjoinをする 3 thread2->Join(); 4 delete thread1; 5 delete thread2; 6} 7

投稿2017/06/05 04:50

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問