よろしくお願いします。
開発環境: Windows 7 32 bit
VS2010 MFC MDI
行いたい処理
・MDI フレームメニューへイベントハンドラを追加し、そのイベントハンドラでモードレ
スダイアログを起動。
・モードレスダイアログへ追加した、開始ボタン押下でワーカースレッド起動。
・ワーカースレッドでは、ドキュメントクラス。及び、関連クラスを用いて、ファイルを
読込み、読み込んだ
ファイルのデータを元に約2000ファイルのダウンロード処理を行う。
・ファイル読込みの進捗を、モードレスダイアログのプログレスバーで表示。
このような処理を行いたいのですが、ワーカースレッドで呼ばれたメソッドから、同じド
キュメントクラスの
ダウンロードメソッドを呼ぶと、ヒープエリアが壊れてしまい、メモリエラーが発生しま
す
スレッド処理の考え方が間違っているのか?実装が間違っているのか?
または、その両方間違っているのか、判断がつきません、ご教示願います。
/*----------------------------------------------------------------------------*/
// DownloadWorkerthred()
/*----------------------------------------------------------------------------*/
/**
* @brief CDownLoadDialogクラスのワーカースレッドから呼ばれて行われる処理
* ダウンロードを行い、パラメータを用い適宜対応するファイル処理を行う
*/
/*----------------------------------------------------------------------------*/
void CxxxDoc::DownloadWorkerthred( PVOID pPara )
{
UINT dlmethod;
CDownLoadDialog* dlg = (CxxxDialog*)pPara;
dlmethod = dlg->GetRadioButton();
FileAccess fa;
std::map<std::string, std::string> mCode;
std::map<std::string, std::string>::iterator it;
fa.readFile();
mCode = fa.getCodeMap();
it=mCode.begin();
while( it != mCode.end() ) {
Download( it->first ); //! この処理を呼ぶと、ヒープが壊れる
it++;
}
}
追記:当該ダウンロード処理は、通常の処理(ワーカースレッドとして呼ばれない場合)
は、正常に動作します。
お世話になります。
MSDN のこのサイトを読みますと。
マルチスレッド : ワーカー スレッドの生成
http://msdn.microsoft.com/ja-jp/library/69644x60(v=vs.80).aspx
参考に下記のように実装しますと、制御するドキュメントクラスのハンドルが取得できて
いないようです
どうしたらいいでしょうか。
UINT MyThreadProc( LPVOID pParam )
{
CxxxDoc* pDoc = CxxxDoc::GetDoc();
if (pDoc == NULL ||
!pDoc->IsKindOf(RUNTIME_CLASS(CxxxDoc)))
return 1; // if pObject is not valid
CxxxDoc *pDoc = (CxxxDoc *)pParam;
pDoc->DownloadWorkerthred(pParam);
return 0;
}
/*----------------------------------------------------------------------------*/
// GetDoc()
/*----------------------------------------------------------------------------*/
/**
* @brief 現在の CDocument または CView からの任意の場所を取得するするに
は、方法
* http://support.microsoft.com/kb/108587/ja
*/
/*----------------------------------------------------------------------------*/
CxxxDoc * CxxxDoc::GetDoc()
{
CMDIChildWnd * pChild =
((CMDIFrameWnd*)(AfxGetApp()->m_pMainWnd))->MDIGetActive();
if ( !pChild )
return NULL; // CxxxDoc::GetDoc();ここでNULLを戻
してしまう。
CDocument * pDoc = pChild->GetActiveDocument();
if ( !pDoc )
return NULL;
// Fail if doc is of wrong kind
if ( ! pDoc->IsKindOf( RUNTIME_CLASS( CxxxDoc ) ) )
return NULL;
return (CxxxDoc *) pDoc;
}
CWnd (およびその派生クラス) は、同一インスタンスを異なるスレッドで使っては
ならないという制約があるので
http://support.microsoft.com/kb/147578/ja
CxxxDoc::GetDoc() は UI スレッド以外から使ってはいけない、のだろう。
どうすればよいか、は
どうしたいか、次第。
まあ普通は、ワーカースレッドからダイアログの HWND に対して (CWnd でなく)
メッセージを送る (PostMessage がよいか SendMessage が良いかは要検討)
ということになるのかな
tetrapod さん。ありがとうございます。
>CWnd (およびその派生クラス) は、同一インスタンスを異なるスレッドで使っては
>ならないという制約があるので
仕様ということで理解しました。
当方で、ドキュメントクラスをインスタンス化すると、余りに挙動がおかしいので
当該ドキュメントクラスで利用したかった、メッソッドを別クラスにて作成し、スレッド
化
してみたところ、いとも簡単に動作しましたので、その方法をとることとしました。