2012-04-23 4 views
2

범위를 벗어난 인덱스에서 액세스하는 것처럼 보이는이 문제를 해결하려고 시도하지만 VS에서 오류가 발생한 곳을 막지 못했습니다. 이게 무슨 원인 이니?디버그 어설 션이 실패했습니다 : std :: vector와 함께 subscript가 범위를 벗어납니다

오류 :

Debug Assertion Failed! Program: .... File: c:\program files\microsoft visual studio 10.0\vc\include\vector Line: 1440 Expression: String subscript out of range

프로그램은 기능 :

스레드 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 :

두 번째 스레드가 구조체에 대한 모습이 아직 보내지라고하며, 그들이 TCP를 통해 전송 될 수 있도록 char 버퍼에 콘텐츠를 저장합니다. 오류의 유형을 정확히 알지는 못했지만 오류 유형을 살펴보면 문자열이나 목록으로 수행하는 것이 었습니다. 그리고 이것은 전체 응용 프로그램의 목록/문자열 (나머지는 일반적인 배열)을 사용하는 유일한 코드입니다. 또한 코드 주석에서 언급 한대로 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 % 확률로 복제 할 수있었습니다 (확실히 다른 경우에도 발생했습니다). 나는 전체 코드를 게시하는 것을 피한다. 왜냐하면 약간 크고 혼란은 피할 수 없기 때문이다. 여기에 오류가 없으면 게시물을 편집하고 더 많은 코드를 추가합니다.

미리 감사드립니다.

+2

목록 개체와 일종의 동기화가 있습니까? 내가 당신의 코드에서 아무것도 볼 수 없기 때문입니다. – mkaes

+0

두 스레드가 동시에 액세스 할 객체를 피하는 것이 좋습니다. –

+0

두 스레드가 동시에 객체를 변경하는 것과 비슷합니다. – juanchopanza

답변

0

여기에 스레드 동기화가없는 것 같습니다. 하나의 스레드가 구조체에서 읽는 동안 다른 구조체가 읽히는 경우 빈 문자열 (또는 그 사이에 무언가가 포함 된 비어 있지 않은 목록)을 포함하여 초기화 중에 읽을 수 있습니다.

게시 된 기능 외부에 뮤텍스 또는 세마포가 없으면 문제 일 수 있습니다.

모든 크기 계산은 내가 그것을 실행하려고하지 않았다 ... 그리고 new wchar_t[_size/2]();에서 <= … -1 대신 <i <= (itr->size()-1)2 대신 sizeof (wchar_t) 조금 이상한 있지만, Windows 용 유효한 것으로 나타납니다.

+0

답변 해 주셔서 감사합니다. 질문을 편집하고 동기화 시도에 대한 세부 정보를 추가했습니다. 귀하가보고 싶어 할 수 있습니다. –

0

코드에 문제가있는 것은 스레드 2가 데이터를 올바르게 대기하고 스레드 1이 스레드에 대해 올바르게 알리는 반면 스레드 2가 스레드 1이 데이터를 처리하는 동안 스레드 1이 아무 것도하지 못하게한다는 것입니다. 이러한 문제를 해결하는 데 사용되는 일반적인 장치는 모니터 패턴입니다.

뮤텍스 (사용자가 액세스 할 때마다 데이터를 보호하기 위해 사용됨)와 조건 변수 (Windows의 경우 = 이벤트)로 구성되어 소비자에게 새로운 데이터에 대한 정보를 전달합니다.

생산자는 일반적으로 뮤텍스를 가져 와서 데이터를 생성하고 뮤텍스를 릴리스 한 다음 이벤트를 시작합니다.

소비자가 더 까다 롭습니다. 뮤텍스를 얻고, 새로운 데이터를 사용할 수 없으면 확인한 다음, 일시적으로 뮤텍스를 해제하는 SignalObjectAndWait 함수를 사용하여 이벤트를 기다린 다음 새로 수집 한 데이터를 처리 한 다음 뮤텍스.

+0

답장을 보내 주셔서 감사합니다. 나는 당신이 제안한 것을 적용하려고 노력하고 있는데, 나는 이것을 쓰레딩하는 방법에 대해 확신 할 수 없다. 내가 뮤텍스를 생성하고'ReleaseMutex'를 사용하여 그것을 풀어주기 위해'CreateMutex'를 호출 할 필요가 있다는 것을 압니다. 그러나 어떻게 그것을 얻을 수 있습니까? 또한'SignalObjectAndWait'를 어떻게 호출해야합니까? 무엇을 기다리고 무엇을 신호해야합니까? –

관련 문제