0

さまざまなスレッドからのデータを xml ファイルに書き込むアプリを作成しています。Event コア オブジェクトを使用して同期しようとしましたが、ファイルで間違ったデータが取得されます。次の結果を得る

<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;
}
4

2 に答える 2

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();
}
于 2012-10-18T12:24:59.250 に答える
0
  1. コードを終了する前に、すべてのスレッドを待つ必要があります

    HANDLE aThread[2];
    
    ...
    
    aThread[0] =  (HANDLE)_beginthreadex(...
    aThread[1] =  (HANDLE)_beginthreadex(...
    
    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
    
  2. 出力を行う前にイベントを待っています。出力が完了したら、ミューテックスを解放します。これは意味がありません。ミューテックスとイベントを待つ必要があります。イベントが設定されると、両方のスレッドの待機が解放されます。したがって、ミューテックスは何もしません。イベント ハンドルとミューテックス ハンドルを 1 つの配列に入れる場合、この目的にも 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;
    }
    

注意: ミューテックスは、並行アプリケーションのリソースを保護するために確立されます。

somePredicat1とについてはわかりませんsomePredicat1。これらのパラメーターは、異なるスレッドで使用される場合にも問題になる可能性があります。ただし、観察した誤った出力は、誤ったミューテックスの使用が原因です。

コメント後に編集:

    if(somePredicat3)
    {
         MyThread(sFileName);
    }

を。スレッドは、ファイルを閉じずに関数として単独で呼び出されます。

b. 目的の詳細を提供する必要がありますsomePredicat3, somePredicat2, and somePredicat1

c. 出力ファイルは複数のスレッドで使用されるため、何らかの排他性で保護する必要があります。そのためにクリティカル セクション オブジェクトを使用することもできます。

于 2012-10-18T12:39:40.143 に答える