VCでスレッドの終了をしたいと考えてます。
自分自身のスレッドを終了するときは、AfxEndThread関数を使うようですが、動作中のスレッドを外から命令して終了させるときはどうすれば良いのか分からないです。教えていただけないでしょうか?

A 回答 (2件)

こんにちは。

itohhといいます。

スレッドを終了させる方法は結構難しいですよ。

TerminateThread 関数を使用すれば、とりあえず強制終了させることは出来ます。
ただし、MSDNライブラリーにも記載されていますが、危険な方法です。
この関数で終了させられたスレッドは、終了処理が出来ません、ということは、
メモリリークを起こす可能性が大です。

一番まともな方法は、WM_CLOSEを対象スレッドにPostMessageすることです。
この場合は、メッセージループを内蔵するユーザーインターフェイススレッド
にする必要があります。
またこの場合でも、デッドロックしているスレッドでは、終了できないと思います。

わたしが、良く行う方法は、
ワーカースレッドの場合:
  ・シグナルを使用して、適時チェックする。(それなりに遅くなるのが難点)
  ・自然に終わるのを待つ。
ユーザーインターフェイススレッドの場合:
  ・WM_CLOSEを対象スレッドにPostMessageする。(デッドロックしないようなロジックにする)
    • good
    • 0
この回答へのお礼

お忙しいところ、ありがとうございました。
スレッドを外から終了させる方法は、まだ検討中なのですが、今のところ、TerminateThread関数を使う予定です。
値の取得、書き込み、描画の処理があるのですがそれぞれに、セマフォを使ってロックし、ロックが終了したタイミングでTerminateThread関数を放とうと計画中です。まだ、VCを触り始めたばかりなので、できるか心配です。でもがんばります。ありがとうございました。

お礼日時:2001/09/14 20:57

動作中のスレッドは常にある変数を監視し、


その変数がある決められた値になった場合に自ら終わるようにする。
外部からスレッドを終了させる場合は、その変数の値を変更するようにする。
かな。
    • good
    • 0
この回答へのお礼

アドバイスありがとうございました。
違う案が聞けて勉強になりました。
お忙しい中、ありがとうございました。

お礼日時:2001/09/17 22:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QVC++ Workerスレッドを強制終了させる方法

VC++6.0でwinアプリを作っています。
ダイアログベースで、ボタンを押すとワーカースレッドを実行し、ここでデータ処理をしています。
もし、スレッド中でデータ処理時間がかかってしまうと、これをスレッド外で強制的に終了させたいですが、出来るのでしょうか。

よろしくお願いします。

Aベストアンサー

>これをスレッド外で強制的に終了させたい
とういうことですが、もしこれを行うと、強制終了させられたスレッドは正規の終了手続きを踏まずに終了します。
そのため、確保したリソースの解放漏れ等が発生しますので、できたらしない方が良いと考えます。
最も簡単な方法は、(ワーカスレッドの作り方にも依存しますが)、フラグによる制御です。
ボタンが押された時、メインスレッドがフラグをオンします。(最初はオフ)
ワーカスレッドは一定間隔(ループしているならループの途中で)で、フラグがオンかどうかをチェックし、オンの場合は自らすみやかに終了するようにします。

QVC++スレッドの正しい終了のさせかた

VC++6.0にてAfxBeginThreadで
m_bAutoDelete = TRUEにてスレッドをおこしております。
この終了時に制御関数のwhileループを脱する様にし、
正常にスレッドを終了させているつもりです。
この後、再度(アプリは継続して起動したまま)
AfxBeginThreadにて全く同じ処理で再開すると、
なぜか、前のスレッドが未だ動作しているかのごとく
制御関数内のTRACEが2重に出力されます。
再度、停止し、またスレッド起動すると、
今度は3重になったかの様な動作をします。

スレッドが正しく終了されていないのでは?と思った現象として、
1回起動時にアプリを終了させると正常終了しますが、
2回起動以上は必ずスレッドのメモリーリークが出ます。
メモリーリーク個所はAfxBeginThreadでした。

制御関数内で必要ないとは思いましたが、終了時に
AfxEndThreadを使用しましたが現象は同じでした。

そこで質問です。
1)この現象は、スレッドが正常に終了されていない事に起因しているのでしょうか?
2)スレッドを正しく終了させるにはどうすればいいのでしょうか?
当方、制御関数がループを抜け、さらにm_bAutoDelete = TRUEであれば
オブジェクトも自動的に破棄されると思っていたのですが。。。

以上、よろしくお願いします。

VC++6.0にてAfxBeginThreadで
m_bAutoDelete = TRUEにてスレッドをおこしております。
この終了時に制御関数のwhileループを脱する様にし、
正常にスレッドを終了させているつもりです。
この後、再度(アプリは継続して起動したまま)
AfxBeginThreadにて全く同じ処理で再開すると、
なぜか、前のスレッドが未だ動作しているかのごとく
制御関数内のTRACEが2重に出力されます。
再度、停止し、またスレッド起動すると、
今度は3重になったかの様な動作をします。

スレッドが正しく終了されていない...続きを読む

Aベストアンサー

 こんばんは。
 AfxEndThread()で起動した物は「m_pThread->PostThreadMessage(WM_QUIT, 0, 0)」で終了させないといけないらしいです。
 http://hp.vector.co.jp/authors/VA014436/prg_memo/windows/vctips/038.html

 試してみましたが、此れで一応綺麗に終るようです。

CWinThread* m_pThread;
bool m_bSuspend = false;

static UINT Proc(LPVOID pData)
{
MSG msg;
CDlg* p = static_cast<CDlg*>(pData);

p->SetDlgItemText(IDC_EDIT1, "START");

while(::GetMessage(&msg, NULL, 0, 0))
{
switch(msg.message)
{
//case WM_QUIT:break;
default:;
}
}
//ココまで来ないといけない
p->SetDlgItemText(IDC_EDIT1, "END");

return 0;
}

void CDlg::OnSwitch()
{
// TODO: この位置にその他の検証用のコードを追加してください
//初めての作成
if(!m_pThread)
{
m_pThread = ::AfxBeginThread(&::Proc, this);
}
else
{
//寝ているスレッドを叩き起こす
if(m_bSuspend)
{
SetDlgItemText(IDC_EDIT1, "RESUME");
m_pThread->ResumeThread();
}
//寝かす
else
{
SetDlgItemText(IDC_EDIT1, "SUSPEND");
m_pThread->SuspendThread();
}

m_bSuspend ^= true;
}
}

void CDlg::OnExit()
{
// TODO: この位置に特別な後処理を追加してください。
if(m_pThread)
{
//寝ているスレッドを叩き起こす(寝ていなければ無視される)
m_pThread->ResumeThread();
m_pThread->PostThreadMessage(WM_QUIT, 0, 0);
m_pThread = 0;
}
}

 こんばんは。
 AfxEndThread()で起動した物は「m_pThread->PostThreadMessage(WM_QUIT, 0, 0)」で終了させないといけないらしいです。
 http://hp.vector.co.jp/authors/VA014436/prg_memo/windows/vctips/038.html

 試してみましたが、此れで一応綺麗に終るようです。

CWinThread* m_pThread;
bool m_bSuspend = false;

static UINT Proc(LPVOID pData)
{
MSG msg;
CDlg* p = static_cast<CDlg*>(pData);

p->SetDlgItemText(IDC_EDIT1, "START");

while(::GetMessage(&msg, NULL, 0, 0...続きを読む

QスレッドAで信号を送り、返答があったときにスレッドBを起動、スレッドAの信号のデータを初期化する方法

VC6.0で開発しています。
今、次のような処理をどうすればよいか悩んでいます。ヒントになる回答を頂けたら幸いです。

データをやり取りする際、どのような処理を行うか命令するもの(以下、命令A)と、命令された通りのデータを送るもの(以下、送信B)、そして、AとBの通信部分を担うもの(以下、通信C)があります。

データのやりとりは、マルチスレッドで行っています。
データをやりとりするために、スレッドが通信C上で2つ起動しています。1つ目のスレッド(以下、スレッドA)は、送信Bが命令Aから送られる特定のデータ(以下、データA)を受け取れるかをどうかの信号を、命令Aに送るためのものです。2つ目のスレッド(以下、スレッドB)は、データAを通信Cが受け取り、送信Bに渡すときに起動するスレッドです。

スレッドAで、送信Bから命令Aへ、受信の準備ができたことを伝える信号が送られます。その後、命令AよりデータAが送られ、通信CでスレッドBが起動するのですが、データAを通信Cで受信したとき、スレッドAで送っている信号を初期化しなければいけません。

データAを受信したときにはスレッドBが起動しますので、スレッドAとスレッドBの間での処理ということになります。

スレッド処理について、まだまだ不勉強なのですが、よいアイディアがあれば教えてください。
よろしくお願いします。

VC6.0で開発しています。
今、次のような処理をどうすればよいか悩んでいます。ヒントになる回答を頂けたら幸いです。

データをやり取りする際、どのような処理を行うか命令するもの(以下、命令A)と、命令された通りのデータを送るもの(以下、送信B)、そして、AとBの通信部分を担うもの(以下、通信C)があります。

データのやりとりは、マルチスレッドで行っています。
データをやりとりするために、スレッドが通信C上で2つ起動しています。1つ目のスレッド(以下、スレッドA)は、送信Bが...続きを読む

Aベストアンサー

アプリ毎に整理してみました。分からないところは想像で書いています。

--命令A--
(1)「命令A→通信C」のファイルを作成。「送信Bが送信Aに対して、データの要求をしているのかを判別するデータを送信しろ」を送る。
(2)「通信C→送信B、命令A」のファイルを監視。「命令Aにデータ要求」が書き込まれるの待つ。
(3)「命令A→通信C」のファイル2を作成。「送信Bの要求データ」を作成する。
(4)「通信C→送信B、命令A」のファイルを監視。「送信Bはデータの要求をしていない」に書き換わるの待つ。
(5)(1)に戻る。

--送信B--
(1)「通信C→送信B、命令A」のファイルを監視。「送信Bが命令Aに対して、データの要求があるか」が書き込まれるのを待つ。
(2)「送信B→通信C」のファイルを作成して、「送信Bが命令Aに対して、データの要求がある」を書き込む。
(3)「通信C→送信B」のファイルが作成されるのを待つ。
(4)ファイルを読んで、データを何らかの手段で送信。
(5)(1)に戻る。

--通信C--
(1)「命令A→通信C」のファイルが作成されるを待つ。
(2)スレッド1を起動する。
(3)「送信B→通信C」のファイルが作成されるのを待つ。
(4)スレッド1に(3)に進むよう指令を出す。
(5)「送信B→通信C」のファイルを削除する。
(6)「命令A→通信C」のファイル2が作成されたことを検出。
(7)スレッド2を起動する。
(8)このあと???

・スレッド1
(1)「通信C→送信B、命令A」のファイルを作成。「送信Bが命令Aに対して、データの要求があるか」を書き込む。
(2)何らかの指令があるまで(1)を繰り返す。
(3)「通信C→送信B、命令A」のファイルを書き換え。「命令Aにデータ要求」に書き換える。
(4)何らかの指令があるまで(3)を繰り返す。
(5)「通信C→送信B、命令A」のファイルを書き換え。「送信Bはデータの要求をしていない」に書き換える。
(6)「命令A→通信C」のファイルを削除する。
(7)スレッドを終了する。

・スレッド2
(1)スレッド1に対して、指令を送り(5)に移行するように促す。
(2)「命令A→通信C」のファイル2を読み込み、「通信C→送信B」のファイルを作成する。コピー後「命令A→通信C」のファイル2は削除する。
(3)スレッドを終了する。

勘違いがあったら訂正をお願いします。

全体として問題を感じたので何点か上げます。
・ファイル作成を条件に動いている所があるが、ファイル内容が全部書き出されていないうちに動き出してしまわないか?
・必要な動作に対してやっていることが複雑である。処理の起点はなぜ送信Bの要求から始まらないのか?命令Aから始まる理由は?
・ファイルの後始末が不明確。
・スレッド1の処理で、何度もファイルを書き換える理由は?
・命令Aと送信Bが通信していれば作れそうな気がする処理で、通信Cが必要な理由が分からない。


シンプルにするとしたら、こんな感じには出来ないのでしょうか?
一応命令Aを起点にしています。スレッドがなくなってしまうので、このアプリの構成がスレッドの勉強のためだったら申し訳ない!

--命令A--
(1)送信Bにメッセージで要求がないか問い合わせる。
(2)送信Bの返事を待つ。
(3)送信要求なら、ファイルを作成する。送信不要なら(1)に戻る。
(4)送信Bにメッセージでファイルが出来たことを知らせる。
(5)送信Bの返事を待つ。
(6)(1)に戻る。

--送信B--
(1)命令Aから要求の問い合わせを待つ。
(2)命令Aにメッセージで要求の有無を送信。
(3)要求無しなら(1)に戻る。
(4)命令Aからファイルの完成メッセージが届くのを待つ。
(5)ファイルを読んで何らかの方法で送信する。
(6)ファイルを削除する。
(7)命令Aにメッセージで送信が完了したことを知らせる。
(8)(1)に戻る。

相互の通信にはWindowsAPIのPostMessageを使用する予定です。
ただし、両方のアプリにhWndが必要なので両方ともウィンドアプリである必要があります。
http://yokohama.cool.ne.jp/chokuto/urawaza/api/PostMessage.html

アプリ毎に整理してみました。分からないところは想像で書いています。

--命令A--
(1)「命令A→通信C」のファイルを作成。「送信Bが送信Aに対して、データの要求をしているのかを判別するデータを送信しろ」を送る。
(2)「通信C→送信B、命令A」のファイルを監視。「命令Aにデータ要求」が書き込まれるの待つ。
(3)「命令A→通信C」のファイル2を作成。「送信Bの要求データ」を作成する。
(4)「通信C→送信B、命令A」のファイルを監視。「送信Bはデータの要求をしていない」に書き換わるの待...続きを読む

Q関数内に関数は無理でしょうか? 子スレッド

CやC++についてまだよくわかっていないのですが、関数内に関数を書くと
「コンパイラ エラー C2601 ローカル関数の定義が正しくありません。」となります。
そこで以下の子スレッドのように関数を関数外に定義して、利用する変数も関数外に定義しました。
変数を外部に定義すると、メモリアクセスになるので、できるだけ避けたかったために
関数内に子スレッドを最初書いていたのですが、何か良い方法はありますか?

子スレッドの引数や戻り値を利用できればいいのですが、そんなことできるのかもわかりません。

あと、関数を配列のように定義できるのでしょうか?
test_thread_0, test_thread_1と逐一書くのが面倒です。

int sum1 = 0, sum2 = 0;

unsigned __stdcall test_thread_0(void *lpx) // lpxはおまじない?
{
// 全て足す
for (int i = ST1; i <= EN1; i++){
sum1 += Data1[i] * Data2[i];
}
return 0; // 正常という意味?
}

unsigned __stdcall test_thread_1(void *lpx)
{
// 全て引く
for (int i = ST2; i <= EN2; i++){
sum2 -= Data1[i] * Data2[i];
}
return 0;
}

CやC++についてまだよくわかっていないのですが、関数内に関数を書くと
「コンパイラ エラー C2601 ローカル関数の定義が正しくありません。」となります。
そこで以下の子スレッドのように関数を関数外に定義して、利用する変数も関数外に定義しました。
変数を外部に定義すると、メモリアクセスになるので、できるだけ避けたかったために
関数内に子スレッドを最初書いていたのですが、何か良い方法はありますか?

子スレッドの引数や戻り値を利用できればいいのですが、そんなことできるのかもわかりま...続きを読む

Aベストアンサー

そもそも関数内の子関数では、スタックを親の関数と共用する前提がありますので、スレッド化することは不可能です。スレッドは専用のスタックを持つことを覚えておいてください。

スレッドは親関数である必要があり、基本的にグローバル領域のメモリかmallocやnewしたヒープ領域のメモリしか参照出来ません。
ローカル変数を受け渡すことは不可能ではないですが、スレッドが動いている間は、そのローカル変数を宣言した関数を抜けることが出来ません。関数を抜けるとローカル変数が保障されなくなるからです。これ理解できますか?

値を返す場合は、CreateThreadの第4パラメータに_biginThreadなら第3パラメータで指定されたポインタ値をスレッドに渡していますので、これを使います。
>unsigned __stdcall test_thread_0(void *lpx) // lpxはおまじない?
このlpxです。
パラメータを渡して、かつ戻り値を受け取りたいなら、lpxに渡すポインタを構造体にすれば複数のポインタを渡すことが出来るので解決できます。理解できますか?

>あと、関数を配列のように定義できるのでしょうか?
>test_thread_0, test_thread_1と逐一書くのが面倒です。
関数参照配列は作れますが、そんなに呼び出すんでしょうか?
配列にするメリットは、添え字で呼び出し関数を切り替えるプログラムを書けるアルゴリズムだった場合だけです。

あと、sum1をグローバル参照にしたくなったとのことですが、ローカル変数にlsumとかを作って計算はそこで行い。最後にsum1=lsum;とすれば解決します。
それとスレッドで参照や変更する変数は、volatile宣言を必ずしてください。
http://proger.blog10.fc2.com/blog-entry-20.html

前に紹介した「APIで学ぶWindows徹底理解」は読みましたか?中途半端な知識でスレッドをやるより、理解が早まるのでぜひ読んでくださいね。
スレッドは覚えること理解することが沢山ありますのでがんばってください!

そもそも関数内の子関数では、スタックを親の関数と共用する前提がありますので、スレッド化することは不可能です。スレッドは専用のスタックを持つことを覚えておいてください。

スレッドは親関数である必要があり、基本的にグローバル領域のメモリかmallocやnewしたヒープ領域のメモリしか参照出来ません。
ローカル変数を受け渡すことは不可能ではないですが、スレッドが動いている間は、そのローカル変数を宣言した関数を抜けることが出来ません。関数を抜けるとローカル変数が保障されなくなるからです。...続きを読む

QVC++2005 VC++6.0で使えた関数がつかえない?(たとえば、GetModuleFileNameとか、、)

VC++超超初心者です。

いままであったVC++6.0で利用できていた、VC++2005で
GetModuleFileNameができなくなりました。
(利用できないことなんて、ないと思いますが、、、)

何か宣言とかinclude文とか必要なのでしょうか。

すみませんが、よろしくお願いします。

Aベストアンサー

VC++2005無料版にはPlatformSDKが別になっているのでそのままでは使えません
別にPlatformSDKをインストールしてVC++2005の設定を変える必要があります
VC++2008では無料版にもSDKが付属しています


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報