スレッドの廃棄について

このQ&Aのポイント
  • スレッドの生成方法として、ボタンのクリックイベントプロシージャ内でCreateThreadを使用しているが、これでは新しいスレッドが生成されるたびに収拾がつかなくなる可能性がある。
  • 一つのスレッドのみを存在させたい場合、スレッドの存在を調べて廃棄し、新しいスレッドを生成する方法が必要。
  • ActiveBasicを使用しているが、CやVBでも同じ方法が適用できる。
回答を見る
  • ベストアンサー

スレッドの廃棄について

ウインドウ上のボタンを押すとあるスレッドがスタートするような プログラムがあるとします。 ボタンのクリックイベントプロシージャ内で 以下のように書いてスレッドをスタートさせることにしたのですが、 Sub MainWnd_CommandButton1_Click() 'スレッドのスタート hThread1=CreateThread(ByVal 0,0,AddressOf(MainOperation),0,0,VarPtr(thread1_ID)) End Sub このままではボタンがクリックされるたびに次々新しくスレッドが 生成されてしまい収拾がつかなくなるのでは?と思います。 基本的に一つのスレッドのみを存在させたいので、 CreateThreadの直前に「CloseHandle(hThread1)」と書こうかとも 思ったのですが、仮にスレッドが存在して無い場合、その場合は 無効なハンドルをクローズすることになりそうで何だか不都合が ありそうです。 スレッドの存在を調べて、あれば安全に廃棄して新しいものをスタート させる、といったことはどのように実装するべきでしょうか? ActiveBasicを使っていますが、教えて頂く際には CやVBでも構いません。

質問者が選んだベストアンサー

  • ベストアンサー
  • buriburi3
  • ベストアンサー率44% (353/792)
回答No.1

スレッド数のカウンタを作ってスレッド起動時にカウントアップ、終了時にカウントダウンしてスレッド数が0でなかったらスレッドを作らないようにする。 作ってから破棄するのではなく、作らないようにすれば良い。 ※Mutexは忘れずに。

jacoby2200
質問者

お礼

回答ありがとうございます。 なるほど、カウンタをこちらで用意してやるんですか。 これだと複数のスレッドを生成したいときでも対応出来ますね。 "作ってから破棄するのではなく、作らないようにすれば良い。" そうですね。その方針で書きたいと思います。 ありがとうございました。またよろしくお願いします。

関連するQ&A

  • スレッドの終了を知りたい(WindowsAPI)

    CreateThread()で作成したスレッドの終了を知りたい (具体的には、スレッドが終了するまで待機したい)のですが、 うまくいかず困っています。WindowsAPIに関する本やネットで調べた ところ、WaitForSingleObject()が適用できると考え、 以下のようなプログラムを作成したのですが、 元のスレッドがWaitForSingleObject()のところで 止まると同時に、CreateThread()で作成されたThread_1()も 止まってしまいます。アドバイスいただけますでしょうか。 ----プログラム(該当部分)ここから---- DWORD Thread_1(LPVOID param) {  int i;  char buff[128];  /* iが99のときのみ終了してよい */  while(g_iFlg == 1)  {   for(i = 0; i < 100; i++)   {    Sleep(100);    wsprintf(buff, "%d", i);    SetDlgItemText((HWND)param, IDC_STATIC_1, buff);   }  }  ExitThread(0);  return 0; } BOOL CALLBACK Proc_2(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {  switch(uMsg)  {   case WM_INITDIALOG:    g_iFlg = 1;    g_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread_1, (LPVOID)hDlg, 0, &g_dwThread);    return TRUE;   case WM_COMMAND:    switch(LOWORD(wParam))    {     case IDC_BUTTON_CANCEL:     case IDCANCEL:      g_iFlg = 0;      WaitForSingleObject(g_hThread, INFINITE);      CloseHandle(g_hThread);      EndDialog(hDlg, 0);      return TRUE;    }  }  return FALSE; } ----プログラム(該当部分)ここまで----

  • CloseHandle()

    スレッドを、同じハンドルを利用して作る場合、 途中でハンドルの開放が必要か教えてください。 void thread1(); HANDLE handle; //スレッド作成 handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread1, NULL, 0, &dwID); //作ったスレッドの終了を待つ WaitForMultipleObjects(1, handle, TRUE, INFINITE); //スレッドを作った時のハンドルを閉じる。これ必要? CloseHandle(handle); //同じハンドルを利用して別のスレッドであるthread2を作成 handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread2, NULL, 0, &dwID); この、CloseHandle(handle);は必要ですか?

  • excelvbaでCreateThreadの動作

    Excel2007で、VBAを利用した簡単なデータエントリ、管理ソフトを作成しています。 ACCESSが無いため、データベースもExcelファイルを使用しています。  ADODBで、データベース用のExcelファイルを開くのですが、エントリ数が増えるに従い、openに時間がかかるようになってきました。そのため、プログレスバーで、VBAが動作していることをアピールすることとしました。  まず、非同期接続を試したのですが、connectionを数回OpenとCloseを繰り返すと、coinitializeでエラーが出てしまい、Excelが落ちる状況となってしまうためあきらめました。  次の手段として、CreateThreadでスレッドを作成して、connectionOpenのスレッドと、プログレスバーのコントロールを分離しようと作成してみましたが、CreateThreadで作成した方のプログラムがうまいこと動作してくれません。  ConnectionOpenをメイン、プログレスバーを別スレッドにしたもの、プログレスバーをメイン、ConnectionOpenを別スレッドにしたものを両方作成してみましたが、どちらも別スレッドにした方がうまく動きません。  debug.print "test"を別スレッドの1行目に入れたところ、イミディエイトに表示されるので、処理が渡っていないわけではないようです。  また、openをメインスレッドにした時にわかっているのは、メインスレッドのADOCon.Openの行が実行されたと同時に、別スレッドが止まってしまっているようです。  もしかして、CreateThreadは割り込みがかけられないような状況では別のスレッドは動作しないのでしょうか?また、CreateThreadで作成されたスレッドは、重たい処理は無理なのでしょうか? テスト用のデータです。 'Busyというユーザーフォームに、PBerというプログレスバーを配置 'C:\Users\xx\Desktop\に、DBファイルを配置 XXは、ユーザー名 'mihon.xlsxは、約5MB '変数等は、両タイプとも共通 Public bRun As Boolean Public adoCON As New ADODB.Connection Public Declare Function CreateThread Lib "kernel32" (ByVal lpThreadAttributes As Long, _ ByVal dwStackSize As Long, ByVal lpStartAddress As Long, _ ByRef lpParameter As Long, ByVal dwCreationFlags As Long, _ ByRef lpThreadID As Long) As Long Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'connectionOpenをメイン、プログレスバーを別スレッド Sub AdoOpen() Dim ThreadId As Long Dim hThread As Long With Busy .BusyMes.Caption = "DB接続処理中" .PBar.Visible = True .PBar.Value = 0 .PBar.Min = 0 .PBar.Max = 10 .Show vbModeless End With DoEvents bRun = False hThread = CreateThread(0&, 0&, AddressOf Counter, 0&, 0&, ThreadId) Application.Wait [NOW()+"0:00:00.5"] With adoCON .Provider = "Microsoft.ACE.OLEDB.12.0" .Properties("Extended Properties") = "Excel 12.0" .Open "C:\Users\xx\Desktop\mihon.xlsx" End With bRun = True If hThread Then CloseHandle hThread hThread = 0 End If With Busy .BusyMes.Caption = "" .PBar.Value = 0 .PBar.Visible = False .Hide End With DoEvents End Sub Function Counter() ' As Boolean Dim bCountup As Boolean Do Until bRun Select Case Busy.PBar.Value Case 0 bCountup = True Case 10 bCountup = False End Select If bCountup Then Busy.PBar.Value = Busy.PBar.Value + 1 Else Busy.PBar.Value = Busy.PBar.Value - 1 End If Sleep 500 Loop End Function 'プログレスバーをメイン、connectionOpenを別スレッド Sub CounterStart() Dim bCountup As Boolean Dim ThreadId As Long Dim hThread As Long 'スレッドハンドル With Busy .BusyMes.Caption = "DB接続処理中" .PBar.Visible = True .PBar.Value = 0 .PBar.Min = 0 .PBar.Max = 10 .Show vbModeless End With DoEvents bRun = False hThread = CreateThread(0&, 0&, AddressOf Counter2, 0&, 0&, ThreadId) Do Until bRun Select Case Busy.PBar.Value Case 0 bCountup = True Case 10 bCountup = False End Select If bCountup Then Busy.PBar.Value = Busy.PBar.Value + 1 Else Busy.PBar.Value = Busy.PBar.Value - 1 End If Application.Wait [NOW()+"0:00:01.5"] Loop If hThread Then CloseHandle hThread hThread = 0 End If With Busy .BusyMes.Caption = "" .PBar.Value = 0 .PBar.Visible = False .Hide End With DoEvents End Sub Function Counter2() With adoCON .Provider = "Microsoft.ACE.OLEDB.12.0" .ConnectionString = "Data Source=" & ObjDB.Value & "; Extended Properties=""Excel 12.0;""" .Open "C:\Users\xx\Desktop\mihon.xlsx" End With bRun = True End Function

  • スレッドで Byref の引数を渡したい場合

    VB2005 の初心者です。 スレッドに Byref の引数を渡すやり方が分かりません。 Byval だとエラーは出ないのですが、 Byref だとどうしてもエラーが消えません。 ソースは下記です。 Private CDF As clsCDF Public Class clsCDF Public LOOP1 As clsLoop1 Public LOOP2 As clsLoop2 End Class Protected Overrides Sub OnStart(ByVal args() As String) Thread = New Thread(AddressOf ABC) Thread.Start(CDF) End Sub Private Sub prvABC ( ByRef CDF As Object ) End Sub 何かヒントになることでも良いので、 皆様の知恵をお借りできれば幸いです。 よろしくお願い致します。

  • Mutexの次の使い方で

    typedef struct{ HWND hwnd;BOOL th_end;HANDLE hmutex; } DATA, *PDATA; /////////////////////////////////////// static HANDLE hThread1,hThread2; DWORD threadID1,threadID2; static DATA data; static HANDLE hMutex; switch (msg) { case WM_CREATE: //hMutex= //CreateMutex(NULL,FALSE,NULL); data.hwnd = hWnd; data.th_end = FALSE; data.hmutex = hMutex; hThread1=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Thread1, (LPVOID)&data, 0,(LPDWORD)&threadID1); hThread2=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Thread2, (LPVOID)&data, 0,(LPDWORD)&threadID2); /*x*/hMutex= /*x*/CreateMutex(NULL,FALSE,NULL); break; とするのは正しくて/*x*/の行を削除して//をとり hMutexの位置を前に持ってくるのは間違っているのでしょうか?

  • スレッドの再開

    MFCでアプリケーションを開発しています。 メインのプログラムを走らせながら計算処理を行いたくて、本やネット等のサンプルプログラムを見ながら別スレッドを生成してみました。 OnInitDialog()でイベントとスレッドを生成し、スタートボタンのクリック押下をトリガーとして、計算処理(Run())を呼んでいます。 タイマー開始後は一定時間ごと(サンプルでは500msec)にスレッドを再開して計算処理を実行し、計算処理完了後はスレッドを一時停止状態にしたいと思っています。 (アプリケーション起動時にサスペンドモードで起動したスレッドをボタン押下でResumeThread(再開)し、あとはタイマーでイベントシグナルをセットして制御するつもりでした。) ですが、下記のコードで走らせると、初回のみ計算処理が呼び出され、その後はスレッドが再開されません(ThreadProc()がコールされない)。 理解不足から何か考え違いをしているのだと思うのですが、どこをなおすべきかわからず行き詰まっています。 どなたかご指摘頂けたらと思います。よろしくお願い致します。 ※実際に記述したコードの抜粋になりますので計算やリソースの解放処理等は省略しています。 OS:Win10 開発環境:VisualStudio2015 C++ ---------------------------------------------------------------- BOOL CMFCApplication1Dlg::OnInitDialog() { CDialog::OnInitDialog(); 中略 … m_hEvent = CreateEventA(NULL, FALSE, FALSE, "EVENT"); m_hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)this, CREATE_SUSPENDED, NULL); return TRUE; } void CMFCApplication1Dlg::OnTimer(UINT_PTR nIDEvent) { switch(nIDEvent) { case 1: { BOOL blRet = SetEvent(m_hEvent); } break; default: { } break; } CDialog::OnTimer(nIDEvent); } UINT CMFCApplication1Dlg::ThreadProc(LPVOID pParam) { CMFCApplication1Dlg* pDlg = dynamic_cast<CMFCApplication1Dlg*>(reinterpret_cast<CWnd*>(pParam)); if(pDlg) { pDlg->ThreadProcCall(); } return 0; } // LineProfileスレッド処理呼び出し. void CMFCApplication1Dlg::ThreadProcCall(void) { // イベントオブジェクト取得. HANDLE h = OpenEventA(EVENT_ALL_ACCESS, FALSE, "EVENT"); // シグナル状態になるまで待機. WaitForSingleObject(h, INFINITE); // 非シグナル状態に. ResetEvent(h); // 計算処理呼び出し. Run(); this->SendMessage(WM_USER_COMPLETE_PROC); } void CMFCApplication1Dlg::Run(void) { // 計算処理. } // LineProfileスレッド終了後処理. afx_msg LRESULT CMFCApplication1Dlg::OnCompleteProc(WPARAM wParam, LPARAM lParam) { // スレッド停止. DWORD dwRet = SuspendThread(m_hThread); return 0; } void CMFCApplication1Dlg::OnBnClickedBtnStart() { // スレッド再開. DWORD dwRet = ResumeThread(m_hThread); // 計算処理呼び出し用タイマー設定. m_nUpdatePaintTimer = SetTimer(1, 500, NULL); }

  • マルチスレッド[ VB.NET 2005 ]

    VB.NET 2005 VC++で作成した通信DLLをマルチスレッドで呼び出すプログラムを作成しています。 マルチスレッドについてご質問です。 ---------------------------------------------------------------- Private Sub ThreadMethod(ByVal aiIndex As UInt32) fSockInit() ← スレッドスタートなので別スレッドで動く End Sub '************************************************** ' フォームロード '************************************************** Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load wkThread(Index) = New Thread(New ThreadStart(AddressOf ThreadMethod)) wkThread(Index).Start() End Sub '************************************************** ' 接続ボタン押下 '************************************************** Private Sub btConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btConnect.Click fConnect() ← スレッドを指定して動かしたい End Sub '************************************************** ' パラメータ設定ボタン押下 '************************************************** Private Sub btParm_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btParm.Click fParmSet() ← スレッドを指定して動かしたい End Sub ---------------------------------------------------------------- 上記の例では、fSockInitはスレッド別に動作しますが、fConnect、fParmSetはメインスレッドで動作するようになっています。 frmMain_Loadで作成したスレッドを指定(※1)して関数を呼び出すことは出来ないのでしょうか? ※1.「クリックイベント(メインスレッド)→実行するスレッドを指定→関数呼び出し→メインスレッドに戻す」の様に。。。

  • VB.NET スレッドからのイベント受信について

    はじめて質問させていただく、VB.NET初心者です。 ただいまスレッド、イベント処理を作成中で Form1にButton1、Label1を貼り付け以下の様なプログラムを記述しました。 (スレッドにて5秒ごとにイベントを発生させます。) 'イベント引数 Public Class EventArgs Inherits System.EventArgs Public nowTime As String End Class 'イベント発行 Public Class EventTest Public Event _event(ByVal sender As Object, ByVal e As EventArgs) Public Sub Go() Dim args As New EventArgs() args.nowTime = Now.ToString RaiseEvent _event(Me, args) End Sub End Class 'フォーム内処理 'スレッド宣言 Dim MyThread As New System.Threading.Thread(AddressOf _Thread) Private WithEvents _test As New EventTest() 'イベント受信   Private Sub Handler(ByVal sender As System.Object, ByVal e As EventArgs) Handles _test._event Label1.Text = e.nowTime End Sub 'スレッド(5秒間隔でイベント発行) Private Sub _Thread() Dim i As Integer For i = 0 To 99 System.Threading.Thread.Sleep(5000) _test.Go() Next End Sub 'スレッド起動 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click MyThread.Start() End Sub End Class 開発環境から普通に実行すれば正常に動作している様なのですが、 イベント受信部(Handler)のLabel1.Text = e.nowTime部に ブレークポイントを置いてLabel1のウォッチをするとその時点で 処理がとまってしまいます。なぜとまるのかが知りたいです。 作成方法がまずいのでしょうか? 皆様よろしくお願いいたします。

  • エクセルマクロ(VBA)での手順

    エクセルマクロ(Vba)にて、ご教示をお願い致します。 ユーザーフォーム上にデータをクリアするコマンドボタンを沢山貼り付けております。 一括クリアするボタンを作成したのですが長文になってしまいます。 Private Sub CommandButton101_Click()   Call CommandButton1_Click   Call CommandButton2_Click   Call CommandButton3_Click   Call CommandButton4_Click   Call CommandButton5_Click   Call CommandButton6_Click ↓ ↓ ↓   Call CommandButton50_Click End Sub 以下のような内容に置き換えたいのですが、上手くいきません。 For i = 1 To 50 Me.Controls ("CommandButton1" & i & "_Click") Next 本を片手に、やっておるのですが行き詰ってしまいました。 お知恵を拝借させてください。 よろしくお願いたします。

  • EXCEL VBAのユーザーフォーム上のテキストボックスの入力方法について

    すいません教えていただきたいことがあります。 EXCEL VBAのユーザーフォームについて、 コマンドボタンにタグを設定して、これにキーボードと同じ機能を持たせて テキストボックス内に入力することは可能でしょうか。 例えばコマンドボタンを「あ」~「ん」まで作り、それぞれのボタンに「あ」~「ん」までのタグを設定する。 Private Sub UserForm_Initialize() CommandButton1.Tag = "あ" CommandButton2.Tag = "い" ・・・・「ん」までボタンを作成する。 次に、 Private Sub CommandButton1_Click() TextBox1.Value = TextBox1.Value & CommandButton1.Tag End Sub Private Sub CommandButton2_Click() TextBox1.Value = TextBox1.Value & CommandButton3.Tag End Sub ・・・「ん」まで作成する。 この設定では、コマンドボタンのクリックで文字の追加はできますが、ボタンを押すと常に文字が一番後ろに追加されるため、 テキストボックスをクリックしても文章の途中に文字を挿入することが出来ません。 通常のキーボードの入力と同じようにテキストボックス内でクリックした箇所からコマンドボタンで入力を開始するような設定は可能でしょうか。 よろしくお願いします。

専門家に質問してみよう