スレッドで行う処理の限界 – プログラミング – Home

スレッドで行う処理の限界
 
通知
すべてクリア

[解決済] スレッドで行う処理の限界

固定ページ 1 / 2

猫柳
 猫柳
(@猫柳)
ゲスト
結合: 18年前
投稿: 11
Topic starter  

今勉強中の初心者の者です。お世話になります。
Visual Studio2005(MFC)でダイアログベースのスレッドを使ったプログラムを作成して
います。
サイズの大きなファイルをcopyしながらプログラスバーを更新し、処理時間を計測する
プログラムです。

前回”MFCのスレッド実行中のコマンド処理“(2007/1/26)で質問で改善したものに時
間計測の処理を加えたものです。

void CnewoneDlg:: copyfile()
{
//省略(ファイルを256バイトづつコピーするループ処理)
// 処 理時間を算出し、時間表示
  //終了時間計測
dtime = difftime(timer2,timer1); //時間差 dtimeはdouble型です
TCHAR strTime[10] = _T(123456789) ; // = _T(") ;
_stprintf_s (strTime, 10, _T(%f), dtime) ;  
     //上が問題 文字列変換します。

// スレッド終了処理。
// ボタン禁止解除
}
UINT CnewoneDlg::CopyThread( LPVOID pParam )
{ //threadからcopyプログラムを呼び出し
// copyfile()の呼び出し
}
void CnewoneDlg::OnBnClickedButton1()
{//ボタンコマンド
// スレッド開始
m_pCopythread = AfxBeginThread( CopyThread, this );//
}
どうも _stprintf_s (…..)を実行するメモリリークすることがわかりました。
Detected memory leaks!
Dumping objects ->
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306) : {124} client
block at 0x003A9890, subtype c0, 68 bytes long.
スレッドの外でテストしたときは問題がなかったです。
Newで割り当てしていないのになぜかと思いましたが、スレッド内できる何らかの限界が
あるんでしょうか?
また、 スレッドCopyThread()内では処理できずに別途関数を呼び出さないといけないの
はなぜでしょうか? 
有効な対策は何でしょう?どなたか教えてください。


引用未解決
トピックタグ
とおりすがり
 とおりすがり
(@とおりすがり)
ゲスト
結合: 23年前
投稿: 180
 

dtime = difftime(timer2,timer1); //時間差 dtimeはdouble型です
TCHAR strTime[10] = _T(123456789) ; // = _T(") ;
_stprintf_s (strTime, 10, _T(%f), dtime) ;  
これいがいのコード削ってもリークしてるの?


返信引用
猫柳
 猫柳
(@猫柳)
ゲスト
結合: 18年前
投稿: 11
Topic starter  

以下の部分を除けばリークはなくなります。
>dtime = difftime(timer2,timer1); //時間差 dtimeはdouble型です
> TCHAR strTime[10] = _T(123456789) ; // = _T(") ;
> _stprintf_s (strTime, 10, _T(%f), dtime) ;

とくに、
> _stprintf_s (strTime, 10, _T(%f), dtime) ;
この行を実行したら、リークして、データが壊れてとまってしまいますね。
逆にファイルコピーの部分をはずしてもうまくいきます。
何らかの制限があるんでしょうかね、、、 


返信引用
超初心者
 超初心者
(@超初心者)
ゲスト
結合: 23年前
投稿: 139
 

変な話だね。
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306)がメモリ確保を
行ったところってことなのかな?


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

>TCHAR strTime[10]
10確保して、
> _stprintf_s (strTime, 10, _T(%f), dtime) ;
これを実行するのは危なくないですか。
仮に100位とってみるとか。


返信引用
猫柳
 猫柳
(@猫柳)
ゲスト
結合: 18年前
投稿: 11
Topic starter  

メモリーリって newで動的に割り当ててデリートしてなかったときに発生するのかの思
っているんですが、ほかにも発生することがあるんですかね。

Dumping objects ->
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306) : {124} client
block at 0x003A9890, subtype c0, 68 bytes long.
私には上のメッセージではどうしたらいいのかわからんです。

ファイルコピーの部分は次の通りです。(openはスレッド起動する前にしてます。)
DWORD nRead = 0, nWriten = 0;
char buff[256];
j = filesize;
while(j > 0){
ReadFile (hf1, buff, sizeof(buff), &nRead, NULL);
WriteFile(hf2, buff, nRead, &nWriten, NULL) ;
j -= nRead ;
}

CloseHandle(hf1) ;
CloseHandle(hf2) ;


返信引用
猫柳
 猫柳
(@猫柳)
ゲスト
結合: 18年前
投稿: 11
Topic starter  

// TCHAR strTime[10] = _T(123456789) ; // = _T(") ;
// size_t a = _tcslen(strTime) + 1;
// _stprintf_s (strTime, 10, _T(%f), dtime) ;
上の部分を次のようにCstring文字列に変えたらうまくいきましたね。
CString strTime ;
dtime = difftime(timer2,timer1);
strTime.Format(_T(%f),dtime) ;

また、実数を
_stprintf (strTime, _T(%f), dtime) ;
とするとRuntime errorでdata破損が出ています。
_stprintf_sの部分が怪しいようです。特に第二引数の部分が関連していると感じます。
文字数は10もじにしているのですが、ためしに20文字にしても同じようです。
今日現象は違うけど、同じことのようです。
MFCのスレッド内で_stprintf_s()とかの関数使えないのかな?


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

dtimeがdouble型で、書式フィールドが%fだと小数点以下に「.000000」がつくけど
その分も考慮して文字列確保してありますでしょうか?

_stprintf (strTime, _T(%d), (int)dtime) ;
ならランタイムエラーがでないと思うけど


返信引用
猫柳
 猫柳
(@猫柳)
ゲスト
結合: 18年前
投稿: 11
Topic starter  

ryoさんのおっしゃるとおりです。
(int)dtimeなら出ません。
それで
size_t a = _tcslen(strTime) + 1;
_stprintf_s (strTime, a, _T(%9.3f), dtime) ;
にしてもうまくいきました。(小数点3桁表示)
スレッド以外で動いていたので問題ないと思っていました。
たまたま問題のないところが壊れていただけなんですね。

ryoさん、みなさんありがとうございます。
素人でいろんなところに気を配らんといけないようですね。
スレッド内だからと限界があるわけではないんですね。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

突き詰めると単純な話で確保した以上のメモリを使っちゃ駄目って事に
つきると思います。なので今回のように出力結果の桁数が変わりうる場合は
考えうる限りの状況から判断して必要十分な量を確保する必要があると言う事です。
なのでできるだけ出力結果の桁数が限定できるようにプログラムを組むとか
そういう工夫が要ります。

なにが怖いって出力結果の最大桁が予想がつかないなんてのが一番性質が悪いです。


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

_stprintf_sですが、C++でコンパイルしていて
第一引数がTCHAR型配列である変数を指定する場合、バッファの指定はなくても動きま
す。

_stprintf_s(strTime, _T(%9.3f), dtime);
(_stprintf_s(sprintf_sまたはswprintf_s)のtemplate版の関数をコールすることにな
る。)

[MSDN]sprintf_s、_sprintf_s_l、swprintf_s、_swprintf_s_l
http://msdn2.microsoft.com/ja-jp/library/ce3zzk1k(VS.80).aspx


返信引用
猫柳
 猫柳
(@猫柳)
ゲスト
結合: 18年前
投稿: 11
Topic starter  

>(_stprintf_s(sprintf_sまたはswprintf_s)のtemplate版の関数をコールすることにな
る。)

情報は知っていましたが、書いてることの意味がわかってきました。

PATIOさん、Blueさん、皆さんありがとうございます。


返信引用
超初心者
 超初心者
(@超初心者)
ゲスト
結合: 23年前
投稿: 139
 

_stprintf_sってバッファのサイズを指定するから
バッファ不足だとしたらすぐにわかるかと思っていた。
少なくともメモリリークになるのが気になる。


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

メモリーリークするのは
バッファぶっ壊しちゃってるため
スレッドが終了するときに
正しくメモリーを解放できなかったからではないかな


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

> 正しくメモリーを解放できなかったからではないかな

多分そうですね。

# バッファ壊した時点で、以後の動作の結果に正しい意味なんてないですし。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました