2012-06-02 17 views
15

मेरे पास एक ऐसा एप्लिकेशन है जो दूसरे थ्रेड को GetMessage() लूप में कॉल करता है। किसी बिंदु पर पहला धागा यह महसूस करता है कि उपयोगकर्ता एप्लिकेशन को छोड़ना चाहता है और दूसरे थ्रेड को सूचित करता है जिसे इसे समाप्त करना चाहिए। चूंकि दूसरा धागा GetMessage() पर फंस गया है, कार्यक्रम कभी नहीं निकलता है। क्या टाइमआउट वाले संदेशों की प्रतीक्षा करने का कोई तरीका है? मैं अन्य विचारों के लिए भी खुला हूं।एक टाइमआउट के साथ GetMessage

संपादित करें:

while (!m_quit && GetMessage(&msg, NULL, 0, 0)) 
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

पहले धागा सच करने के लिए सेट m_quit: (अतिरिक्त स्पष्टीकरण)

दूसरा धागा कोड की है कि टुकड़ा चलाता है।

+0

प्रतीक्षा करें ... लूप में कौन सा धागा 'GetMessage() 'पर प्रतीक्षा कर रहा है? पहला धागा, दूसरा धागा, या दोनों? – templatetypedef

+0

दूसरा धागा GetMessage लूप चलाता है। क्या मुझे कुछ कोड पोस्ट करना चाहिए? – qdii

+0

कोड हमेशा मदद करता है। मैं सिर्फ उलझन में हूं क्योंकि आपका प्रश्न ऐसा लगता है कि दोनों धागे अवरुद्ध हैं। क्या आप सिर्फ एक कस्टम संदेश नहीं भेज सकते हैं "आपको अभी बंद करने की आवश्यकता है?" – templatetypedef

उत्तर

13

GetMessage पर कॉल करने से पहले UINT_PTR timerId=SetTimer(NULL, NULL, 1000, NULL) पर कॉल करना सबसे आसान तरीका है। यह WM_TIMER संदेश को हर सेकेंड कॉलिंग थ्रेड पर पोस्ट करेगा, इसलिए GetMessage तत्काल वापस आ जाएगा। फिर, इसे रद्द करने के लिए KillTimer(NULL, timerId) पर कॉल करें।

अद्यतन नमूना कोड:

BOOL GetMessageWithTimeout(MSG *msg, UINT to) 
{ 
    BOOL res; 
    UINT_PTR timerId = SetTimer(NULL, NULL, to, NULL); 
    res = GetMessage(msg); 
    KillTimer(NULL, timerId); 
    if (!res) 
     return FALSE; 
    if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == timerId) 
     return FALSE; //TIMEOUT! You could call SetLastError() or something... 
    return TRUE; 
} 
+0

बल्कि अजीब watchdog =) – Forgottn

+0

@rodrigo: +1। अब तक का सबसे अच्छा समाधान मैंने देखा है। मैं अन्य उम्मीदवारों को दिखाने के लिए इंतजार करूंगा। – qdii

+0

@rodrigo 'msg' के लिए बाहर देखो एक सूचक है। भी, निर्देशित संरचना में 'uMsg' सदस्य नहीं है, इसे' संदेश 'कहा जाता है। – qdii

-1

हाँ। इसके बजाय PeekMessage() आज़माएं। लेकिन मुझे लगता है कि यह पूरी समस्या हल नहीं होगी।

+0

@ फोर्गोथ कॉलिंग 'पीक मेसेज()' एक अच्छा समाधान होगा यदि मैं इसे 'नींद (1000)' के साथ जोड़ सकता हूं, लेकिन मेरे मामले में दूसरा धागा बहुत प्रतिक्रियाशील होना चाहिए। +1 क्योंकि समाधान अन्य संदर्भों में मान्य है – qdii

4

एक बात तुम हमेशा करते है बस अवरुद्ध धागा उपयोगकर्ता परिभाषित संदेश है कि यह जगाने के लिए कारण होगा, संदेश प्रक्रिया भेज सकते हैं, तो वापस जाने के लिए लूप के शीर्ष पर। वास्तव में, m_quit वैरिएबल को पूरी तरह से निकालने के लिए सबसे आसान हो सकता है और इसके बजाय मुख्य थ्रेड को केवल एक संदेश भेजने के लिए कहा जाता है, "आपको अभी छोड़ना होगा।"

आशा है कि इससे मदद मिलती है!

+1

+1, यह मदद करता है। मैं रॉड्रिगो के समाधान को पसंद करता हूं क्योंकि यह एक ही स्थान पर पूरी छोड़ने वाली तंत्र को रखता है। – qdii

+1

यह एक बहुत साफ विधि है। धागे का बिंदु संदेश प्राप्त करना है जो बताता है कि क्या करना है। और ऐसा करने के लिए कुछ भी नहीं होने पर थ्रेड को लगातार जागने की आवश्यकता नहीं होती है। –

2

आपको दूसरे थ्रेड पर PostThreadMessage के साथ एक संदेश छोड़ने में सक्षम होना चाहिए।

उदा।

PostThreadMessage(threadid, WM_QUIT, 0, 0); 

आप दूसरे सूत्र में m_quit चर पढ़ने की जरूरत नहीं होनी चाहिए, लेकिन आप GetMessage के साथ-साथ FALSE/0 की वापसी मान जो दिया जाता है है से त्रुटियों के लिए जाँच करनी चाहिए अगर अगले संदेश एक छोड़ दिया संदेश है ।

18

परीक्षण नहीं किया गया है, लेकिन आप बिना किसी ऑब्जेक्ट के MsgWaitForMultipleObjects फ़ंक्शन को आजमा सकते हैं।

MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_ALLEVENTS); 

अगर रिटर्न WAIT_TIMEOUT यह एक समय समाप्ति है, लेकिन अगर यह रिटर्न WAIT_OBJECT_0 आप गारंटी के साथ GetMessage नहीं अवरुद्ध किया जा करने के लिए कॉल कर सकते हैं।

लेकिन ध्यान दें निम्नलिखित:

MsgWaitForMultipleObjects वापस नहीं करता है अगर वहाँ संदेश कतार में निर्दिष्ट प्रकार के अपठित इनपुट के बाद धागा कतार जाँच करने के लिए एक समारोह का आह्वान किया है।

तो आपको यह सुनिश्चित करना होगा कि पिछली बार जब आप किसी भी संदेश फ़ंक्शन को बुलाते हैं तो कतार पर कोई संदेश नहीं छोड़ा जाता है, या आपके पास एक प्रकार की दौड़ स्थिति होगी।

शायद अपने सबसे अच्छे विकल्प के साथ GetMessage को बदलने के लिए होगा:

if (MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_ALLEVENTS) == WAIT_OBJECT_0) 
{ 
    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) 
    { 
     //dispatch the message 
    } 
} 

लेकिन जैसा कि मैंने पहले कहा, मैं परीक्षण नहीं लगा कि यह तो मुझे यकीन है कि अगर यह काम करेगा नहीं हो सकता।

+1

आह यह घटना बेहतर है – qdii

+8

मेरे पास इस दिनचर्या के साथ ** SendMessage ** msgstr "के लिए प्रतीक्षा में एक डेडलॉक था। आपको ** QS_ALLEVENTS ** की बजाय ** QS_ALLINPUT ** का उपयोग करना चाहिए, क्योंकि इसमें ** QS_SENDMESSAGE ** भी शामिल है। अधिक जानकारी के लिए [msdn] देखें (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684242%28v=vs.85%29.aspx) – 5andr0

+0

धन्यवाद @ 5andr0 'QS_ALLINPUT' क्या था मेरे लिए तय किया! – Noitidart

संबंधित मुद्दे