2

範囲外のインデックスでアクセスしているように見えるこの問題を修正しようとしていますが、VSはエラーが発生した場所で停止できず、原因について混乱しています。

エラー:

デバッグアサーションに失敗しました!プログラム:....ファイル:c:\ program files \ microsoft visual studio 10.0 \ vc \ include \ vector行:1440式:文字列の添え字が範囲外です

プログラムの機能:

2つのスレッドがあります:

スレッド1:

最初のスレッドは、(とりわけ)を使用して現在のウィンドウの変更を探しますGetForegroundWindow()。チェックはループではなく、WH_MOUSE_LLイベントがトリガーされたときに行われます。データは固定サイズの構造体に分割されるため、tcpを介してサーバーに送信できます。最初のスレッドは、データ(ウィンドウタイトル)をstd::list現在の構造体のに記録します。

if(change_in_window)
{
    GetWindowTextW(hActWin,wTitle,256);
    std::wstring title(wTitle);
    current_struct->titles.push_back(title);
}

スレッド2:

2番目のスレッドは、まだ送信されていない構造体を探すために呼び出さcharれ、tcpを介して送信できるように、コンテンツをバッファーに入れます。エラーがどこにあるか正確にはわかりませんが、エラーのタイプから見ると、文字列またはリストのいずれかで発生しました。これは、リスト/文字列を使用するアプリケーション全体からの唯一のコードです(残りは従来の配列です)。また、コードコメントで説明されているようにifブロックにコメントを付けると、エラーが発生しなくなります。

  BOOL SendStruct(DATABLOCK data_block,bool sycn)
    {
    [..]

                int _size = 0;
// Important note, when this if block is commented the error ceases to exist, so it has something to do with the following block
                if(!data_block.titles.empty()) //check if std::list is empty
                {

                    for (std::list<std::wstring>::iterator itr  = data_block.titles.begin(); itr != data_block.titles.end() ; itr++) {
                        _size += (((*itr).size()+1) * 2); 
                    } //calculate size required. Note the +1 is for an extra character between every title
                    wchar_t* wnd_wbuffer = new wchar_t[_size/2](); //allocate space
                    int _last = 0;
    //loop through every string and every char of a string and write them down
                    for (std::list<std::wstring>::iterator itr = data_block.titles.begin(); itr != data_block.titles.end(); itr++)
                    {
                        for(unsigned int i = 0; i <= (itr->size()-1); i++)
                        {

                            wnd_wbuffer[i+_last] = (*itr)[i] ;
                        }
                        wnd_wbuffer[_last+itr->size()] = 0x00A6; // separator
                        _last += itr->size()+1;
                    }

                    unsigned char* wnd_buffer = new unsigned char[_size];
                    wnd_buffer = (unsigned char*)wnd_wbuffer;
                    h_io->header_w_size = _size;
                    h_io->header_io_wnd = 1;
                    Connect(mode,*header,conn,buffer_in_bytes,wnd_buffer,_size);
                    delete wnd_wbuffer;
                }
                else
            [..]
                return true;
            }

スレッド同期の試み: 作成された最初のdata_blockへのポインター(db_main)現在のdata_blockへのポインター(db_cur)

//datablock format
    typedef struct _DATABLOCK
        {
            [..]
            int logs[512];
            std::list<std::wstring> titles;
            bool bPrsd; // has this datablock been sent true/false
            bool bFull; // is logs[512] full true/false
            [..]
            struct _DATABLOCK *next;
        } DATABLOCK;    


//This is what thread 1 does when it needs to register a mouse press and it is called like this:
    if(change_in_window)
    {
        GetWindowTextW(hActWin,wTitle,256);
        std::wstring title(wTitle);
        current_struct->titles.push_back(title);
    }
    RegisterMousePress(args);
    [..]
//pseudo-code to simplify things , although original function does the exact same thing. 
    RegisterMousePress()
        {
            if(it_is_full)
            {
                db_cur->bFull= true;
                if(does db_main exist)
                {
                    db_main = new DATABLOCK;
                    db_main = db_cur;
                    db_main->next = NULL;
                }
                else
                {
                    db_cur->next = new DATABLOCK;
                    db_cur = db_cur->next;
                    db_cur->next = NULL;

                }
                SetEvent(eProcessed); //tell thread 2 there is at least one datablock ready
            }
            else
            {
            write_to_it();
            }
        }
//this is actual code and entry point of thread 2 and my attempy at synchronization
    DWORD WINAPI InitQueueThread(void* Param)
    {
        DWORD rc;
        DATABLOCK* k;
        SockWClient writer;
        k = db_main;
        while(true)
        {
            rc=WaitForSingleObject(eProcessed,INFINITE);
            if (rc== WAIT_OBJECT_0)
            {   
                do
                {
                    if(k->bPrsd)
                    {
                        continue;
                    }
                    else
                    {   
                        if(!k)
                        {break;}
                        k->bPrsd = TRUE;
    #ifdef DEBUG_NET
                        SendStruct(...);
    #endif

                    }
                    if(k->next == NULL || k->next->bPrsd ==TRUE || !(k->next->bFull))
                    {
                        ResetEvent(eProcessed);
                        break;
                    }

                } while (k = k->next); // next element after each loop
            }
        }
        return 1;

    }

詳細:

サブストリングエラーは非常にまれであるため、エラーはそこにはないと私は信じています。Mouse_Down + Wnd + Tabを押してウィンドウをスクロールし、しばらく押し続けた場合にのみ、100%の確率で再現できました(他の場合にも発生しました)。コード全体が少し大きく、混乱が避けられないため、コード全体を投稿することは避けています。エラーがここにない場合は、投稿を編集してコードを追加します。

前もって感謝します

4

2 に答える 2

0

ここでは、スレッドの同期は行われていないようです。1 つのスレッドが構造体から読み取り、もう 1 つのスレッドが書き込みを行っている場合、初期化中に読み取られ、空の文字列 (または間に無効なもの) を含む空でないリストが含まれる可能性があります。

投稿された関数の外側にミューテックスまたはセマフォがない場合、それが問題である可能性があります。

すべてのサイズ計算は Windows で有効であるように見えますが、実行しようとはしませんでした…そしてin とin の<= … -1代わりは少し奇妙です。<i <= (itr->size()-1)2sizeof (wchar_t)new wchar_t[_size/2]();

于 2012-04-23T14:41:06.437 に答える
0

コードの問題は、スレッド 2 がデータを正しく待機し、スレッド 1 がそれ​​らについて正しく通知している間、スレッド 2 は、スレッド 1 がデータを処理している間、スレッド 1 がその手の下で何かを行うことを妨げないことです。このような問題を解決するための代表的な装置がモニターパターンです。

これは、1 つのミューテックス (データを保護するために使用され、アクセスするたびに保持されます) と条件変数 (Windows 用語ではイベント) で構成され、新しいデータに関する情報をコンシューマーに伝えます。

通常、プロデューサーはミューテックスを取得し、データを生成し、ミューテックスを解放してから、イベントを発生させます。

コンシューマはさらに複雑です。ミューテックスを取得し、新しいデータが利用可能になっていないかどうかを確認し、ミューテックスを一時的に解放する SignalObjectAndWait 関数を使用してイベントを待機し、新しく取得したデータを処理してミューテックスを解放する必要があります。

于 2012-04-23T22:49:36.073 に答える