2012-02-10 17 views
6

Bối cảnh:Tại sao chuỗi win32 không tự động thoát?

Trong ứng dụng của tôi viết bằng C++, tôi tạo ra một sợi công nhân do đó tạo ra hai luồng sử dụng CreateThread(). Hai luồng mà thread công nhân tạo ra, nói chuyện với WCF Service thông qua một máy khách được thực hiện bằng cách sử dụng Windows Web Services API, cung cấp giao diện lập trình ứng dụng C/C++ (API) để xây dựng các dịch vụ web và khách hàng dựa trên SOAP cho họ. Ứng dụng của tôi triển khai chỉ ứng dụng khách sử dụng API này.

Vấn đề:

Vấn đề tôi đang phải đối mặt là tất cả các chủ đề khác kết thúc tốt đẹp, ngoại trừ các sợi nhân, như bạn có thể nhìn thấy mình, trong hình dưới đây WorkerThreadProc mà không sử dụng chu kỳ CPU nhưng nó doesn 't thoát. Ngoài ra còn có vài chủ đề khác chạy mà không được tạo ra bởi tôi, nhưng theo thời gian chạy.

bang

Các chủ đề như sau (theo báo cáo của ProcessExplorer):

  • WorkerThreadProc là trong Chờ: WrUserRequest nhà nước.
  • wWinMainCRTStartup đang ở trạng thái Đợi: Trạng thái UserRequest.
  • Tất cả TpCallbackIndependent đang ở trạng thái Chờ: WrQueue.

Họ còn chờ gì nữa? Những nguyên nhân có thể có mà tôi cần phải xem xét là gì? Ngoài ra, sự khác nhau giữa WrUserRequestUserRequest là gì? Và WrQueue có nghĩa là gì? Tôi hoàn toàn không biết chuyện gì đang diễn ra ở đây.

enter image description here


Đây là mã WorkerThreadProc tôi. Tôi đã gỡ bỏ tất cả các báo cáo khai thác gỗ ngoại trừ người cuối cùng ở dưới cùng của hàm:

DWORD WINAPI WorkerThreadProc(PVOID pVoid) 
{ 

    //Initialize GDI+ 
    GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR   gdiplusToken; 

    Status status = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 
    if (status != Status::Ok) 
    { 
     return 1; 
    } 

    GuiThreadData *pGuiData = (GuiThreadData*)pVoid; 

    auto patternIdRequestQueue= new PatternIdRequestQueue(); 
    auto resultQueue = new ResultQueue(); 

    auto patternManager = new PatternManager(patternIdRequestQueue); 
    LocalScheduler *pScheduler = new LocalScheduler(resultQueue, patternManager); 

    bool bInitializationDone = pScheduler->Initialize(pGuiData->m_lpCmdLine); 
    if (!bInitializationDone) 
    { 
     return 0; 
    } 

    //PatternIdThread 
    PatternIdThread patternIdThread(patternIdRequestQueue); 
    DWORD dwPatternIdThreadId; 
    HANDLE hPatternIdThread = CreateThread(NULL, 0, PatternIdThreadProc, &patternIdThread, 0, &dwPatternIdThreadId); 

    ResultPersistence resultPersistence(resultQueue); 
    DWORD dwResultPersistenceThreadId; 
    HANDLE hResultPersistenceThread = CreateThread(NULL, 0, ResultPersistenceThreadProc, &resultPersistence, 0, &dwResultPersistenceThreadId); 

    pScheduler->ScheduleWork(pGuiData->m_hWnd, pGuiData->m_hInstance, ss.str()); 

    pScheduler->WaitTillDone(); 
    patternIdThread.Close(); 
    resultPersistence.Close(); 

    delete pScheduler; 

    //Uninitialize GDI+ 
    GdiplusShutdown(gdiplusToken); 

    dwRet = WaitForSingleObject(hPatternIdThread, INFINITE); 
    CloseHandle(hPatternIdThread); 

    dwRet = WaitForSingleObject(hResultPersistenceThread,INFINITE); 
    CloseHandle(hResultPersistenceThread); 

    SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0); 

    //IMPORTANT : this verbose message is getting logged! 
    T_VERBOSE(EvtSrcInsightAnalysis, 0, 0, "After sending message to destroy window"); 

    delete patternManager; 
    delete patternIdRequestQueue; 
    delete resultQueue; 
    return 0; 
} 

Hãy xem T_VERBOSE vĩ mô, nó được sử dụng để đăng nhập thông điệp dài dòng. Tôi thấy thông báo đang được ghi lại, nhưng chuỗi không thoát!


EDIT:

Tôi chỉ nhận xét dòng sau trong tôi WorkerThreadProc, sau đó sợi nhân thoát duyên dáng!

SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0); 

Có nghĩa là SendMessage là thủ phạm? Tại sao nó sẽ chặn chuỗi chủ đề gọi?

+0

Bạn đang gọi CloseHandle() trên tay cầm chủ đề sau khi nó thoát? Bạn nên sử dụng WaitForSingleObject() để đợi kết thúc. –

+0

@infact: Tất nhiên, có! Và vâng, tôi đang sử dụng 'WaitForSingleObject' để đợi kết thúc! – Nawaz

+0

Tại sao bạn không sử dụng trừu tượng như 'boost :: thread' được chứng minh là hoạt động tốt (và thậm chí là di động)? – PlasmaHH

Trả lời

3

Nếu chúng ta nhìn vào các tài liệu cho SendMessage, bạn có thể nhìn thấy quote ít này:

Để gửi tin nhắn và trả lại ngay lập tức, sử dụng SendMessageCallback hoặc SendNotifyMessage chức năng. Để đăng một tin nhắn đến một tin nhắn của thread và trả lại ngay lập tức, hãy sử dụng chức năng PostMessage hoặc PostThreadMessage .

và điều này:

Tin nhắn được gửi giữa các chủ đề được xử lý chỉ khi nhận thread thực thi mã truy nhắn. Chủ đề gửi bị chặn cho đến khi luồng nhận được xử lý tin nhắn. Tuy nhiên, chuỗi gửi sẽ xử lý các thư không được gửi đến trong khi đợi thông báo của nó được xử lý. Để ngăn chặn điều này, hãy sử dụng SendMessageTimeout với SMTO_BLOCK được đặt. Để biết thêm thông tin về các thông báo không được trả lời, hãy xem Tin nhắn không được trả lời.

vì vậy chúng tôi có thể thấy SendMessage sẽ chặn cho đến khi thư được xử lý, bằng cách nào đó dẫn đến bế tắc trong mã của bạn, vì msgproc không nằm trong chuỗi công nhân của bạn, dẫn đến chuyển ngữ cảnh (chỉ được kích hoạt khi hàng đợi của luồng được bơm cho các tin nhắn). Hãy thử sử dụng PostMessage, trả về ngay lập tức.

EDIT: đó cũng là một chút mảnh tốt đẹp của thông tin here trên deadlocks nhắn từ SendMessage

+0

Sau khi tìm ra vấn đề với 'SendMessage()' (như tôi đã đăng câu hỏi này), tôi đọc doc (mà bạn đã đăng là câu trả lời) trên MSDN, nhưng điều tôi không hiểu là tại sao ' SendMessage' không trả về. Nó không trả về có nghĩa là luồng nhận không xử lý các thông điệp, điều này có nghĩa là nếu tôi sử dụng 'PostMessage', thì nó sẽ không xử lý các thông báo ngay cả sau đó. Mặc dù, nó sẽ giải quyết vấn đề chặn luồng, nhưng vấn đề thực sự (mà chúng ta * bây giờ * biết) vẫn còn đó, đó là điều này: các thông báo không được xử lý! – Nawaz

+0

@Nawaz: Phần đó sẽ được giải quyết tốt hơn bằng cách sử dụng một cái gì đó như Spy ++, tôi cũng phải đối mặt với một vấn đề tương tự với các thư 'WM_CLOSE' không được xử lý, truy xuất nó trở lại một thông báo cửa sổ khác trả về giá trị sai, dẫn đến thư' WM_CLOSE' bị xóa khỏi hàng đợi để không thể xử lý – Necrolis

Các vấn đề liên quan