2012-10-18 6 views
0

다른 스레드의 데이터를 XML 파일에 쓰는 앱을 작성하고 있습니다. 내가 이벤트 코어 개체를 사용하여 동기화하려고하지만 파일에서 잘못된 데이터가 발생합니다. 나는 다음 결과를다른 스레드의 동기화 출력 스트림

<file path="somePath" /> 
<file path="somePath" <file path="somePath" /> />.... 

얻을하지만 난

<file path="somePath" /> 
<file path="somePath" /> 
<file path="somePath" /> 

내 의사 코드 아래 참조 얻을 것으로 기대합니다. 뭐가 잘못 됐어?

unsigned int WINAPI MyThread(void *p) 
{ 
    std::wofstream outstr; 
    outstr.open("indexingtest.xml", std::ios::app); 
    do 
    { 
     if(somePredicat1) 
     { 
      WaitForSingleObject(hEvent, INFINITE); 
      outstr <<"<file path=\""<< sFileName << "\"\n"; 
      outstr <<"\tsize=\""<< fileSize << "\" />\n";   
      ReleaseMutex(hMutex); 
     } 
     if(somePredicat3) 
     { 
      MyThread(sFileName); 
     } 
    }while(somePredicat2); 
    outstr.close(); 
    FindClose(hSearch); 
    return 0; 
} 

int _tmain(int argc, TCHAR *argv[]) 
{ 
    hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
    //hMutex = CreateMutex(NULL, FALSE, 0); 
    unsigned int ThreadID; 
    HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, MyThread, L"D:\\*", 0, &ThreadID); 
    HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, MyThread, L"C:\\*", 0, &ThreadID); 
    SetEvent(hEvent); 
    std::wcout << "\a" << std::endl; 
    WaitForSingleObject(hThread1, INFINITE); 
    return 0; 
} 

더 구체적인 코드

HANDLE hMutex = CreateMutex(NULL,FALSE, 0); 
wchar_t** GetAllFilesImpl(wchar_t const* folder, wchar_t** res, size_t* pAllocated, size_t* pUsed) 
{ 
    HANDLE hSearch; 
    WIN32_FIND_DATAW fileinfo; 
    size_t allocatedMemory = 0; 


    hSearch = FindFirstFileW(folder, &fileinfo); 
    if(hSearch != INVALID_HANDLE_VALUE) { 
     do { 

      wchar_t* sFileName, ** tmp, sTmp[ 1024 ]; 
      long fileSize = 0; 
      long creationDate; 
      /* ignore ., .. */ 
      if(!wcscmp(fileinfo.cFileName, L".") || 
       !wcscmp(fileinfo.cFileName, L"..")) 
       continue; 
      sFileName = PathCreator(folder, fileinfo.cFileName); 
      fileSize = fileinfo.nFileSizeLow; 
      creationDate = fileinfo.ftCreationTime.dwHighDateTime; 


      if(fileSize) 
      { 
       WaitForSingleObject(hMutex, INFINITE); 
       std::wofstream outstr; 
          outstr.open("indexingtest.xml", std::ios::app); 
       outstr.seekp(std::ios_base::end); 
       outstr <<"<file path=\""<< sFileName << "\"\n"; 
       outstr <<"\tsize=\""<< fileSize << "\" />\n"; 
       outstr.seekp(std::ios_base::end); 
       outstr.close(); 
       wprintf(L"%s\n", sFileName); 
       ReleaseMutex(hMutex); 
      } 

      tmp = AddToArray(res, pAllocated, pUsed, sFileName); 
      if(!tmp) return FreeAllFilesMemory(res), NULL; 
      res = tmp; 

      if(fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 
       wcscpy_s(sTmp, sFileName); 
       wcscat_s(sTmp, L"\\*"); 
       tmp = GetAllFilesImpl(sTmp, res, pAllocated, pUsed); 
       if(!tmp) return NULL; 
       res = tmp; 
      } 
     } while(FindNextFileW(hSearch, &fileinfo)); 

     FindClose(hSearch); 
    } 
    return res; 
} 

unsigned int WINAPI GetAllFiles(void* folder) 
{ 
    size_t nAllocated = 0, nUsed = 0; 
    wchar_t** res = GetAllFilesImpl((wchar_t *)folder, NULL, &nAllocated, &nUsed); 
    if(res) { 
     /* to indicate end of result add a NULL string */ 
     wchar_t** tmp = AddToArray(res, &nAllocated, &nUsed, NULL); 
     if(!tmp) return FreeAllFilesMemory(res), -1; 
     res = tmp; 
    } 
    std::wcout << "\a" << std::endl; 
    return 0; 
} 
int _tmain(int argc, TCHAR *argv[]) 
{ 

    Sleep(1000); 
    unsigned int ThreadID; 
    HANDLE hThreads[3]; 
    hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, GetAllFiles, L"D:\\*", 0, &ThreadID); 
    hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, GetAllFiles, L"C:\\Users\\Andrew\\Desktop\\*", 0, &ThreadID); 
    hThreads[2] = (HANDLE)_beginthreadex(NULL, 0, GetAllFiles, L"E:\\*", 0, &ThreadID); 
    unsigned int dw = WaitForMultipleObjects(3, hThreads, TRUE, INFINITE); 
    CloseHandle(hFile); 
    printf("finished\n"); 
    return 0; 
} 

답변

2

당신이 가지고있는 문제는 각 스레드는 별도로 파일을 여는 것입니다. 대신 파일을 열고 스레드를 만든 다음 뮤텍스를 사용하여 파일에 쓰기를 동기화하십시오. 의사 코드에서

: 당신이 당신의 출력을하기 전에

std::wofstream output_file; 

void my_thread() 
{ 
    do 
    { 
     if (some_condition) 
     { 
      lock_mutex(); 
      do_output(); 
      unlock_mutex(); 
     } 
    } while (condition); 
} 

int main() 
{ 
    output_file.open(...); 

    create_thread(); 
    create_thread(); 

    output_file.close(); 
} 
+0

이렇게하면 모든 데이터가 파일에 혼란스러워지는 것은 아닙니다. 스레드 함수에 재귀가 있다고 말하는 것을 잊어 버렸습니다. 질문의 판을보십시오. – abilash

+0

O 죄송합니다. 잘못된 문서를 수정했습니다. – abilash

0
  1. 당신은 모든 스레드 기다려야 코드

    HANDLE aThread[2]; 
    
    ... 
    
    aThread[0] = (HANDLE)_beginthreadex(... 
    aThread[1] = (HANDLE)_beginthreadex(... 
    
    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE); 
    
  2. 를 종료하기 전에 이벤트를 기다리고 있습니다. 출력을 완료하면 뮤텍스를 해제합니다. 이것은 말이되지 않습니다. 뮤텍스를 기다리고 이벤트를 기다려야합니다. 이벤트가 설정되면 두 스레드가 모두 대기 상태가됩니다. 따라서 뮤텍스는 아무 것도하지 않습니다. 당신은 하나 개의 배열로 이벤트 핸들과 뮤텍스 핸들을 넣을 때 , 당신도이 목적을 위해 와 WaitForMultipleObjects를 사용할 수 있습니다

    HANDLE hVarious[2]; 
    hVarious[0] = CreateEvent(NULL, TRUE, FALSE, NULL); 
    // Note: this is a manual reset event. 
    // Thus is stays set until explicitly reset 
    
    hVarious[1] = CreateMutex(NULL, FALSE, 0); 
    
    // and now start the threads: 
    aThread[0] = (HANDLE)_beginthreadex(... 
    aThread[1] = (HANDLE)_beginthreadex(... 
    
    // and set the event: 
    SetEvent(hEvent); 
    
    
    WaitForMultipleObjects(2, aThread, TRUE, INFINITE); 
    

    스레드는 다음과 같아야합니다

    unsigned int WINAPI MyThread(void *p) 
    { 
        do 
        { 
        if(somePredicat1) 
        { 
         // wait for the mutex AND the event 
         WaitForMultipleObjects(2, hVarious, TRUE, INFINITE); 
    
         // do the file stuff in the mutex protected part  
         std::wofstream outstr; 
         outstr.open("indexingtest.xml", std::ios::app); 
    
         outstr <<"<file path=\""<< sFileName << "\"\n"; 
         outstr <<"\tsize=\""<< fileSize << "\" />\n";   
    
         outstr.close(); 
         FindClose(hSearch); 
         ReleaseMutex(hVarious[1]); 
        } 
        }while(somePredicat2); 
        return 0; 
    } 
    

기억하십시오 : mutex는 동시 응용 프로그램의 자원을 보호하기 위해 설정됩니다.

somePredicat1somePredicat1에 대해 알지 못합니다. 이러한 매개 변수는 다른 스레드에서 사용될 때 문제가 될 수도 있습니다. 그러나 잘못된 출력은 잘못된 뮤텍스 사용으로 인해 발생합니다. 코멘트 후

편집 :

if(somePredicat3) 
    { 
     MyThread(sFileName); 
    } 

가. 스레드는 파일을 닫지 않고 함수로 자체 호출됩니다.

b. somePredicat3, somePredicat2, and somePredicat1에 대한 자세한 내용을 제공해야합니다.

c. 둘 이상의 스레드가 을 사용하기 때문에 출력 파일을 독점 성으로 보호해야합니다. 또한 Critical Section Object을 사용하면됩니다.

+0

코드에서 뮤텍스를 사용하지 않는 것은 오타입니다. 그것은 주석 처리되어야합니다. 이벤트 코어 객체를 사용하여 동기화하고 싶습니다. 내가 WaitForMultipleObjects()하려고하지만 그것은 도움이되지 않습니다. 나는 틀린 것을 모른다. 내 코드는 문자열의 thousends를 출력해야하며 거의 모든 것이 올 바릅니다. 그러나 약 10 개가 혼합되어 있습니다 (contein 2 행 하나). 무엇이 잘못 될 수 있습니까 ... – abilash

+0

오타가 ... 흠. 그래서 여러분은 이미 문제를 해결하기 위해 뮤텍스 (mutex)를 실험 해 보았습니다. 이것이 올바른 접근이었습니다. 왜 그걸 포기 했습니까? 편집 된 답변을 참조하십시오. – Arno

+0

뮤텍스와 케이스를 추가했습니다. 실제 코드는 – abilash