범위를 벗어난 인덱스에서 액세스하는 것처럼 보이는이 문제를 해결하려고 시도하지만 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 % 확률로 복제 할 수있었습니다 (확실히 다른 경우에도 발생했습니다). 나는 전체 코드를 게시하는 것을 피한다. 왜냐하면 약간 크고 혼란은 피할 수 없기 때문이다. 여기에 오류가 없으면 게시물을 편집하고 더 많은 코드를 추가합니다.
미리 감사드립니다.
목록 개체와 일종의 동기화가 있습니까? 내가 당신의 코드에서 아무것도 볼 수 없기 때문입니다. – mkaes
두 스레드가 동시에 액세스 할 객체를 피하는 것이 좋습니다. –
두 스레드가 동시에 객체를 변경하는 것과 비슷합니다. – juanchopanza