プロが教える店舗&オフィスのセキュリティ対策術

実際のプログラムでバグが出たので、簡易化したプログラムでテストしてみましたがどこが悪いのか分かりませんでした。

#include <WinSock2.h>
#include <vector>
#include <process.h>
#include <algorithm>
#include <stdio.h>

using namespace std;

CRITICAL_SECTION cs;

unsigned __stdcall Login( void * );

int main()
{
    vector<unsigned int> thID;
    vector<HANDLE> hTh;

    for( int i=0 ; i<10 ; i++ )
    {
        printf( "メインスレッド:%d\n", i );
        if( (i%2) == 0 )
        {
            thID.push_back( i );
            hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Login, &i, 0, &thID[i]) );
        }
    }

    while(1)
    {
        for( int i=0 ; i<10 ; i++ )
        {
            if( hTh[i] != NULL )
            {
                CloseHandle(hTh[i]);
            }
        }

        char a[2];
        scanf( "%c", a );
        if( strcmp( a, "X" ) == 0 )
        {
            return 0;
        }
    }
}

unsigned __stdcall Login( void *Num )
{
int *a = (int *)Num;
for( int i=0 ; i<10 ; i++ )
{
printf( "サブスレッド%d:%d\n", *a, i );
}
return 0;
}

出るエラーは以下のようになります

Windows によって Server.exe でブレークポイントが発生しました。
ヒープが壊れていることが原因として考えられます。Server.exe または読み込まれた DLL にバグがあります。
あるいは、Server.exe がフォーカスを持っているときに、ユーザーが F12 キーを押したことが原因として考えられます。
可能であれば、出力ウィンドウに詳細な診断情報が表示されます。

if( (i%2) == 0 )
をコメントアウトするとエラーは出ません

また、共に
表示される例として(見やすいように空行あり)
以下のように、
スレッド番号が+1されていたり(A)
各スレッド内のループ回数が直前のスレッドの回数を引き継いでいたり(B)
スレッドのループ回数が初期化されていたり(C)
呼び出されてないはずのスレッドが起動していたり(D)
します

メインスレッド:0
メインスレッド:1

サブスレッド1:0 ・・・・・・A(本来はサブスレッド0のはず)
サブスレッド1:1

メインスレッド:2

サブスレッド2:3 ・・・・・・B(本来はサブスレッド2:0のはず)
サブスレッド2:4
サブスレッド2:5

サブスレッド1:0 ・・・・・・C(本来は1:3のはず)
サブスレッド1:1

サブスレッド2:0

サブスレッド3:0 ・・・・・・D(本来はまだ起動してないはず)
サブスレッド3:1

メインスレッド:3


どこを直せばいいか教えてください

A 回答 (4件)

> では、どのようにしたらいいのでしょうか?



たとえばこんな:

#include <WinSock2.h>
#include <vector>
#include <tuple>
#include <process.h>
#include <algorithm>
#include <stdio.h>

using namespace std;

CRITICAL_SECTION cs;

unsigned __stdcall Login( void * );

int main() {
typedef tuple<unsigned int, HANDLE, int> record;
vector<record> records;

for( int i=0 ; i<10 ; i++ ) {
printf( "メインスレッド:%d\n", i );
if ( (i%2) == 0 ) {
records.push_back(record());
record& r = records.back();
get<2>(r) = i;
get<1>(r) = (HANDLE)_beginthreadex(NULL, 0, Login, &get<2>(r), 0, &get<0>(r) );
}
}
...
    • good
    • 0
この回答へのお礼

わざわざありがとうございます。
tupleという物があるんですね。
知らなかったです

調べてみましたが、どういうものかは分かりましたがプログラムで何をしているのか分からなかったのでそのままコピペしてみました

結果
メインスレッド:0~9
サブスレッド-17891602:0~9
サブスレッド0:0~9
サブスレッド-17891602:0~9
サブスレッド-17891602:0~9
サブスレッド8:0~9
となりました

大体道筋が見えてきたように思います。

お礼日時:2012/07/01 23:13

今現在の問題のあるコードと実行結果を貼って下さい。

この回答への補足

あ、申し訳ありません

前略
{
    vector<unsigned int> thID;
    vector<HANDLE> hTh;
    DWORD dwExCode;

    for( int i=0 ; i<10 ; i++ )
    {
        printf( "\nメインスレッド:%d\n", i );
        if( (i%2) == 0 )
        {
            thID.push_back( i );
            hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Login, &i, 0, &thID[i/2]) );
        }
    }

    while(1)
    {
        for( int i=0 ; i<hTh.size() ; i++ )
        {
            GetExitCodeThread(hTh[i], &dwExCode);
            if( dwExCode != STILL_ACTIVE )
            {
                CloseHandle( hTh[i] );

                vector<HANDLE>::iterator end_it = remove( hTh.begin(), hTh.end(), HANDLE(hTh[i]) );
                hTh.erase( end_it, hTh.end() );

                vector<unsigned int>::iterator End_it = remove( thID.begin(), thID.end(), unsigned int(thID[i]) );
                thID.erase( End_it, thID.end() );
            }
        }
        char a[2];
        scanf( "%c", a );
        if( strcmp( a, "X" ) == 0 )
        {
            return 0;
        }
    }
}
以下略

結果の一例
M:0
M:1
M:2

S2:0
S3:1~9

M:3
M:4

S3:0
S4:1
S5:2~9

M:5
M:6

S5:0
S7:1

M:7
M:8

S7:2
S9:3~9

補足日時:2012/07/01 19:11
    • good
    • 0

怪しい所です。


1.スレッドに変数寿命が切れたローカル変数iを渡している。
2.vectorでpush_backした要素数よりも多い番号を参照。
(i%2) == 0 )で2回に一回しかpush_backしないのに&thID[i]でi番目を参照しています。
3.以下の部分は10個要素がある前提に成っているが10個無いのでエラーです。
 for( int i=0 ; i<10 ; i++ )
        {
            if( hTh[i] != NULL )
            {
                CloseHandle(hTh[i]);
            }
        }
4.スレッドの終了を待たずにCloseHandleしている。

この回答への補足

2.3.4.を直しました
各スレッド内のループ回数が直前のスレッドのループ回数を引き継いでいるのは直りませんでした

補足日時:2012/07/01 17:02
    • good
    • 0
この回答へのお礼

1.はepistemeさんと同じことですよね?
2.3.あ、本当ですね。だから偶数のときにスレッドを立てるようにしたらエラーになったんですね
4.そこは盲点でした。

とりあえず、2.3.4.を直してこようと思います

お礼日時:2012/07/01 16:29

 for( int i=0 ; i<10 ; i++ ) {


  ...
  hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Login, &i, 0, &thID[i]) );

コロコロ変化している i のポインタを スレッドに引き渡しているのはおかしくない?
スレッドに火が付いた時点で i が変化してるかもですよ?
    • good
    • 0
この回答へのお礼

なるほど。確かにそうですね

では、どのようにしたらいいのでしょうか?

お礼日時:2012/07/01 16:26

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