"Not Responding" वास्तव में क्या है — Windows ऐप के हैंग का निर्णय कैसे करता है, और न हैंग करने वाले ऐप कैसे डिज़ाइन करें
· Go Komura · Windows, Windows विकास, समस्या निवारण, मल्टीथ्रेडिंग, WinForms, WPF, Win32 API, UI डिज़ाइन
“ऑपरेशन के बीच ऐप सफेद हो जाता है और (Not Responding) दिखाता है।” “हमें टिकट मिलते हैं कि कभी-कभी हैंग होता है, पर विकास मशीन पर कभी पुनरुत्पादित नहीं होता।” — Windows व्यावसायिक ऐप के लिए यह “Not Responding” सबसे आम शिकायतों में से एक है। और आश्चर्यजनक रूप से कम ज्ञात यह है कि “Not Responding” प्रदर्शन लगाने वाली चीज़ हैंग ऐप स्वयं नहीं — वह OS है।
Windows कैसे जानता है कि ऐप “हैंग” हो गया? वह पाले-जैसी सफेद विंडो क्या है? Windows पर व्यावसायिक ऐप लिखने वाले डेवलपरों और हैंग ऐप के टिकट लेने वाले IT कर्मचारियों के लिए, यह लेख मैसेज लूप की बुनियाद से “Not Responding” निर्णय चलाता है, और हैंग के क्लासिक कारण, न हैंग करने वाले डिज़ाइन, तथा हैंग क्षण जाँचने की प्रक्रिया — सब प्राथमिक स्रोतों पर आधारित — व्यवस्थित करता है।
1. निष्कर्ष पहले
- “Not Responding” OS का निर्णय है। जब विंडो (और उसका स्वामी GUI थ्रेड) इनपुट की प्रतीक्षा न कर रही हो, स्टार्टअप अनुक्रम में न हो, और 5 सेकंड से संदेश (
PeekMessage) न लिया हो, तो OS उसे प्रतिक्रिया न देने वाला मानता है। निर्णय प्रति-प्रोसेस नहीं।1 - सफेदी वाली विंडो “घोस्ट विंडो” है। OS ने मूल विंडो छिपाई और उसी स्थिति, आकार, और रूप की नकली लगा दी। केवल खिसका, न्यूनतम, या बंद कर सकते हैं; सामग्री नहीं चल रही। डीबगर जुड़े रहते घोस्ट विंडो नहीं बनती।2
- हैंग का कारण लगभग हमेशा एक बात पर आता है। जो UI थ्रेड मैसेज लूप पंप कर रहा होना चाहिए वह भारी काम या प्रतीक्षा पर ब्लॉक है। सिंक्रोनस I/O, नेटवर्क कॉल, लॉक प्रतीक्षा, और थ्रेड पार
SendMessageक्लासिक हैं।3 - डिज़ाइन सिद्धांत है “UI थ्रेड पर प्रतीक्षा या गणना न करें”। भारी काम वर्कर थ्रेड पर ले जाएँ (C# में
async/await+Task.Run) और UI थ्रेड को पेंटिंग, प्रगति, और रद्दीकरण स्वीकार के लिए समर्पित रखें।4 DoEventsऔर मैन्युअल मैसेज लूप पंप पुनःप्रवेश बग का प्रजनन स्थल हैं। “Not Responding” प्रदर्शन चला जाता है, पर संरचना अब मनमाने इवेंट को काम के बीच व्यवधान देने देती है। टालना नहीं, पृथक्करण उचित तरीका है।- जाँच हैंग क्षण की अवस्था पकड़ने से शुरू होती है। डंप लें और UI थ्रेड का स्टैक देखें, तो लगभग हमेशा पहचान सकते हैं कि वह किसकी प्रतीक्षा कर रहा है।
2. पूर्वापेक्षा: Windows ऐप संदेशों से चालित होते हैं
“Not Responding” समझने के लिए, पहले यह समझना चाहिए कि Windows GUI ऐप इवेंट-चालित है। GUI ऐप इनपुट स्वयं जाकर नहीं लाता; वह OS द्वारा दिए संदेश (माउस, कीबोर्ड, पुनर्पेंट अनुरोध, टाइमर, आदि) पाता है और उन पर काम करता है।3
हर थ्रेड जो विंडो बनाता है उसके पास मैसेज कतार होती है और वह ऐसा मैसेज लूप चलाता है।
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg); // the window procedure is called
}
GetMessage कतार से संदेश लेता है, और DispatchMessage उस विंडो की विंडो प्रोसीजर (संदेश-सँभाल फ़ंक्शन) बुलाता है। बटन-क्लिक सँभाल, पुनर्पेंट, और WinForms या WPF इवेंट हैंडलर सब, उबालने पर, इस लूप के एक चक्र के भीतर चलते हैं।5
flowchart TB
accTitle: मैसेज लूप की बुनियादी संरचना
accDescr: OS माउस, कीबोर्ड, और अन्य इनपुट थ्रेड की मैसेज कतार में रखता है; UI थ्रेड का लूप उसे GetMessage से लेता है, DispatchMessage से विंडो प्रोसीजर बुलाता है, और प्रोसेसिंग खत्म होने पर लूप के शीर्ष पर लौटता है
os["OS(इनपुट, पुनर्पेंट अनुरोध, टाइमर)"] --> q["थ्रेड मैसेज कतार"]
q --> gm["GetMessage से लें"]
gm --> dm["DispatchMessage"]
dm --> wp["विंडो प्रोसीजर में सँभालें"]
wp --> gm
चित्र 1: GUI ऐप का हृदय मैसेज लूप है; हर इवेंट हैंडलर इस लूप के एक चक्र के रूप में चलता है।
इस संरचना का एक महत्त्वपूर्ण परिणाम है। यदि विंडो प्रोसीजर (इवेंट हैंडलर) के भीतर समय लेने वाला काम करें, तो लूप उस बीच अगला संदेश नहीं ले सकता। न क्लिक पर प्रतिक्रिया दे सकता है न पुनर्पेंट अनुरोध पर — यही “हैंग” वास्तव में है।
यह भी समझना चाहिए कि संदेश दो पथों से दिए जाते हैं। PostMessage संदेश कतार पर रखता और तुरंत लौटता है, और लूप संदेश क्रम से लेता और संसाधित करता है। SendMessage, दूसरी ओर, विंडो प्रोसीजर सीधे बुलाता है और प्रोसेसिंग पूरी होने तक कॉलर पर नहीं लौटता।36 वह अंतर अध्याय 4 की डेडलॉक चर्चा में सीधा जाता है।
flowchart TB
accTitle: संदेश पहुँचाने के दो पथ
accDescr: PostMessage संदेश कतार पर रखता और तुरंत लौटता है; मैसेज लूप संदेश क्रम से लेता और संसाधित करता है। SendMessage विंडो प्रोसीजर सीधे बुलाता है और प्रोसेसिंग पूरी होने तक कॉलर पर नहीं लौटता
pm["PostMessage"] --> q2["कतार पर रखें(तुरंत लौटता है)"]
q2 --> loop["लूप क्रम से लेता और संसाधित करता है"]
sm["SendMessage"] --> direct["प्रोसीजर सीधे बुलाएँ"]
direct --> w2["प्रोसेसिंग पूरी होने तक नहीं लौटता"]
चित्र 2: दोनों “संदेश भेजते” हैं, पर कतार वाला Post और पूर्णता की प्रतीक्षा करने वाला Send पूरी तरह भिन्न स्वभाव रखते हैं।
3. “Not Responding” का निर्णय कैसे होता है — 5-सेकंड नियम और घोस्ट विंडो
तो OS कैसे जानता है कि “यह ऐप हैंग हो गया”? कसौटी आधिकारिक रूप से दस्तावेज़ीकृत है। OS विंडो को प्रतिक्रिया न देने वाली तब मानता है जब वह इनपुट की प्रतीक्षा न कर रही हो, स्टार्टअप अनुक्रम में न हो, और 5 सेकंड से PeekMessage (संदेश लेना) न बुलाया हो।1 अर्थात्, OS देखता है कि “मैसेज लूप वास्तव में घूम रहा है” जैसे नाड़ी लें, और यदि 5 सेकंड नाड़ी न हो तो विंडो को प्रतिक्रिया न देने वाली मानता है (दस्तावेज़ कहता है कि यह 5-सेकंड मान भविष्य में बदल सकता है)। निर्णय की इकाई विंडो और उसका स्वामी GUI थ्रेड है; कई UI थ्रेड वाले ऐप में एक थ्रेड हैंग होने का अर्थ दूसरे थ्रेड की विंडो मरी नहीं। डंप में देखने वाला थ्रेड हैंग विंडो का स्वामी है।
जिस शीर्ष-स्तरीय विंडो का निर्णय हो चुका उसके साथ क्या होता है यह भी दस्तावेज़ीकृत है। OS मूल विंडो छिपाता है और उसी Z-क्रम, स्थिति, आकार, और रूप की “घोस्ट विंडो” से बदल देता है। उपयोगकर्ता केवल खिसका, आकार बदल, या (जबरन) बंद कर सकता है। भीतर का ऐप वास्तव में प्रतिक्रिया नहीं दे रहा, इसलिए अन्य ऑपरेशन काम नहीं करते।2
flowchart TB
accTitle: हैंग-विंडो निर्णय और घोस्ट-विंडो अदला-बदली
accDescr: जब UI थ्रेड भारी काम पर ब्लॉक हो और संदेश लेना 5 सेकंड रुक जाए, OS विंडो को प्रतिक्रिया न देने वाली मानता है, मूल छिपाता है, उसी रूप की घोस्ट विंडो लगाता है, और उपयोगकर्ता को केवल खिसकाना, न्यूनतम, और बंद देना है
busy["UI थ्रेड भारी काम पर ब्लॉक"] --> stop["संदेश लेना रुकता है"]
stop --> judge{"5 सेकंड बीते?"}
judge -->|"नहीं"| stop
judge -->|"हाँ"| ghost["घोस्ट विंडो लगाएँ"]
ghost --> u1["टाइटल दिखाता है(Not Responding)"]
ghost --> u2["पाले-जैसी सफेदी; केवल खिसका और बंद"]
चित्र 3: “Not Responding” पाठ और सफेद स्क्रीन दोनों OS द्वारा लगाई घोस्ट विंडो की हैं, हैंग ऐप की नहीं।
टाइटल बार पर दिखने वाला “(Not Responding)” स्ट्रिंग, और Aero थीम के अधीन पाले-जैसी सफेदी, दोनों इसी घोस्ट विंडो की हैं। दो व्यावहारिक परिणाम निकलते हैं।
- “Not Responding” दिखने तक, उस विंडो का स्वामी थ्रेड कम से कम 5 सेकंड संदेश संसाधित नहीं कर रहा। यह नहीं कि “प्रदर्शन जल्दी आ गया” — UI थ्रेड निश्चित रूप से ब्लॉक है।
- डीबगर जुड़े रहते घोस्ट विंडो नहीं बनती।2 जब ऐसा लगे कि “डीबगर के अधीन कभी Not Responding नहीं जाता, पर रिलीज़ में जाता है”, हैंग स्वयं वही हो सकता है और केवल प्रदर्शन भिन्न।
एक API भी है, DisableProcessWindowsGhosting, जो इस अदला-बदली को पूरे प्रोसेस के लिए अक्षम करती है।7 यह कियोस्क टर्मिनल जैसे विशेष मामलों के लिए है जहाँ आप नहीं चाहते कि OS स्वयं विंडो को संचालित दिखाने लगे। इसे कॉल करने से “Not Responding” प्रदर्शन आना रुकता है, पर ऐप हैंग है यह तथ्य नहीं बदलता। समझें कि सामान्य ऐप इसे “Not Responding” उपाय के रूप में उपयोग नहीं करता।
4. ऐप क्यों हैंग होते हैं — UI थ्रेड ब्लॉक करने वाले क्लासिक पैटर्न
कारण, उबालने पर, एक बिंदु है — “UI थ्रेड मैसेज लूप पर नहीं लौटता” — पर व्यवहार में जो रूप मिलते हैं वे कुछ क्लासिक में पड़ते हैं।
flowchart TB
accTitle: UI थ्रेड ब्लॉक करने वाले क्लासिक कारणों का वर्गीकरण
accDescr: चार क्लासिक परिवार — सिंक्रोनस I/O और नेटवर्क कॉल, लॉक प्रतीक्षा, थ्रेड पार SendMessage, और COM STA संलग्नता — सभी उसी एक बिंदु पर आते हैं कि UI थ्रेड मैसेज लूप पर नहीं लौट सकता
kind{"कौन सा क्लासिक कारण?"}
kind --> io{"I/O या लॉक?"}
kind --> other{"SendMessage या COM?"}
io --> c1["सिंक I/O और नेटवर्क"]
io --> c2["लॉक प्रतीक्षा"]
other --> c3["SendMessage"]
c3 -.-> c3n["थ्रेड पार"]
other --> c4["COM STA संलग्नता"]
c1 --> core["UI लौट नहीं सकता"]
c2 --> core
c3 --> core
c4 --> core
core --> ar["Not Responding जाँच"]
चित्र 4: दिखने वाला लक्षण एक है, पर थ्रेड ब्लॉक करने वाला अपराधी चार परिवारों में पड़ता है, और उपाय प्रत्येक के लिए भिन्न है।
सिंक्रोनस I/O और नेटवर्क कॉल। यह सबसे आम है। बटन-क्लिक हैंडलर के भीतर बड़ी फ़ाइल पढ़ना या लिखना, डेटाबेस क्वेरी, Web API कॉल, या नेटवर्क ड्राइव पर फ़ाइल पहुँच सिंक्रोनस करने का पैटर्न। विकास मशीन पर यह सेकंड के अंश में खत्म होता है, इसलिए पता नहीं चलता; उत्पादन नेटवर्क विलंब या फ़ाइल-सर्वर हिचक दसियों सेकंड की प्रतीक्षा बना देता है, और टिकट आते हैं कि “कभी-कभी हैंग होता है”। नेटवर्क ड्राइव कनेक्शन गिरने पर लंबे टाइमआउट रखते हैं, और लक्षण नाटकीय रूप से बदतर करते हैं।
लॉक प्रतीक्षा। वह पैटर्न जिसमें UI थ्रेड वर्कर थ्रेड से साझा डेटा पर लॉक लेने की कोशिश करता है, और उस लॉक को लंबे समय पकड़े वर्कर की प्रतीक्षा में फँस जाता है। लॉक अनुशासन व्यावहारिक मल्टीथ्रेडिंग श्रृंखला में विस्तार से है।
थ्रेड पार SendMessage। SendMessage गंतव्य विंडो की प्रोसीजर प्रोसेसिंग पूरी करने तक नहीं लौटता।6 जब दूसरे थ्रेड की विंडो पर भेजें, भेजने वाले को तब तक प्रतीक्षा करवाई जाती है जब तक वह थ्रेड संदेश संसाधित कर सकने वाली अवस्था में हो। यदि गंतव्य थ्रेड स्वयं किसी चीज़ की प्रतीक्षा कर रहा हो, तो मैसेज डेडलॉक होता है जिसमें हर पक्ष दूसरे की प्रतीक्षा करता है।3 विशेषकर HWND_BROADCAST पर भेजना आपको खींच लेगा जैसे ही एक विंडो प्रतिक्रिया न दे। जब प्रतीक्षा नहीं कर सकते, SendMessageTimeout या उत्तर की प्रतीक्षा न करने वाला PostMessage सोचें।8
sequenceDiagram
accTitle: थ्रेड पार SendMessage से डेडलॉक
accDescr: यदि वर्कर थ्रेड UI-थ्रेड विंडो पर SendMessage भेजे जबकि UI थ्रेड वर्कर के परिणाम की प्रतीक्षा में ब्लॉक हो, हर पक्ष दूसरे के खत्म होने की प्रतीक्षा करता है और डेडलॉक होता है
participant U as UI थ्रेड
participant W as वर्कर थ्रेड
U->>U: वर्कर के खत्म होने की प्रतीक्षा(ब्लॉक)
W->>U: SendMessage(संसाधित होने तक नहीं लौटता)
Note over U: संदेश संसाधित नहीं कर सकता(ब्लॉक)
Note over W: SendMessage से नहीं लौट सकता
Note over U,W: एक-दूसरे की प्रतीक्षा — डेडलॉक
चित्र 5: “UI थ्रेड वर्कर की प्रतीक्षा करे, और वर्कर SendMessage से UI थ्रेड की प्रतीक्षा करे” क्लासिक डेडलॉक है।
COM अपार्टमेंट संलग्नता। STA ऑब्जेक्ट की कॉल विंडो संदेश के रूप में दी जाती हैं, इसलिए जब UI थ्रेड (STA) ब्लॉक हो, अन्य थ्रेड से COM कॉल भी संपार्श्विक रूप से ब्लॉक हो जाती हैं। वह संरचना COM STA/MTA लेख में समझाई गई है।
“यह तो क्षण भर है” का ढेर। 50 ms की सिंक्रोनस कॉल भी, लूप में 100 बार बुलाई, 5 सेकंड है। Not Responding सीमा 5 सेकंड है, पर महसूस होने वाली “सुस्ती” लगभग 100 ms से शुरू होती है। डिज़ाइन का अंगूठा नियम है “UI थ्रेड केवल मिलीसेकंड के लिए ब्लॉक हो सकता है”।
5. न हैंग करने वाले डिज़ाइन — भारी काम को UI थ्रेड से हटाना
डिज़ाइन सिद्धांत एक बात है: समय लेने वाला काम UI थ्रेड से हटाएँ। C# (WinForms/WPF) में, async/await सबसे छोटा उचित तरीका है।
private async void RunButton_Click(object sender, EventArgs e)
{
runButton.Enabled = false;
try
{
// CPU-heavy work, or APIs that are only synchronous, go to a worker via Task.Run
var result = await Task.Run(() => HeavyCalculation(input));
// For I/O, use APIs that are natively async (they do not consume a thread either)
var data = await httpClient.GetStringAsync(url);
// After await you are back on the UI thread, so you can touch controls directly
resultLabel.Text = result + data.Length.ToString();
}
catch (Exception ex)
{
// An exception leaking from an async void handler will take the app down. Catch it here
MessageBox.Show($"The operation failed: {ex.Message}");
}
finally
{
runButton.Enabled = true;
}
}
तीन बिंदु हैं। पहला, await प्रतीक्षा करते UI थ्रेड मैसेज लूप में वापस होता है, इसलिए Not Responding नहीं जाते। दूसरा, await के बाद निरंतरता UI थ्रेड पर लौटती है, इसलिए बाद में कंट्रोल सामान्य छू सकते हैं (वर्कर थ्रेड से कंट्रोल सीधे छूना वर्जित है; यदि चाहिए तो Control.Invoke / Dispatcher.InvokeAsync उपयोग करें)।4 तीसरा, काम चलते बटन अक्षम करें, और अन्यथा डिज़ाइन से पुनःप्रवेश मारें।
रूप नेटिव Win32 में वही है: काम वर्कर थ्रेड को सौंपें, पूर्णता UI थ्रेड को PostMessage से कस्टम संदेश के रूप में सूचित करें, और विंडो प्रोसीजर में UI अपडेट करें। PostMessage केवल संदेश कतार पर रखता और तुरंत लौटता है, इसलिए वर्कर पक्ष भी ब्लॉक नहीं होता।6 वर्कर थ्रेड की प्रतीक्षा स्वयं कंडीशन-वेरिएबल लेख में वर्णित अनुशासन से लिखें।
flowchart TB
accTitle: न हैंग करने वाले ऐप में भूमिकाओं का विभाजन
accDescr: UI थ्रेड केवल इनपुट स्वीकार, प्रगति दिखाना, और रद्दीकरण स्वीकार के लिए जिम्मेदार है; वर्कर थ्रेड भारी काम चलाता है और पूर्णता UI थ्रेड को PostMessage या await निरंतरता से लौटाता है
ui["UI थ्रेड: इनपुट, प्रगति, रद्द"] -->|"काम सौंपें"| w["वर्कर थ्रेड: भारी काम"]
w -->|"PostMessage / await निरंतरता"| ui
ui -.-> ng["UI थ्रेड पर सिंक्रोनस I/O या लंबी गणना नहीं"]
चित्र 6: UI थ्रेड को “रिसेप्शन डेस्क” रखें, भारी काम हमेशा वर्कर को सौंपें, और केवल पूर्णता सूचना लें।
जो बचाना चाहिए वह तकनीक है भारी काम के टुकड़ों के बीच केवल प्रदर्शन जीवित रखने के लिए Application.DoEvents() या PeekMessage लूप घुसाना। Not Responding टलता है, पर मनमाने इवेंट हैंडलर काम के बीच पुनः-प्रवेश करते हैं। बटन का दूसरा क्लिक, प्रोसेसिंग के दौरान फ़ॉर्म बंद करना, टाइमर फायर — कोई भी अभी संसाधित डेटा दूषित कर सकता है, और बग समय-निर्भर तथा कठिन-पुनरुत्पादन होते हैं। मैन्युअल मैसेज लूप पंप को मोडल प्रगति डायलॉग जैसी सीमित संरचना के भीतर रखें, और नियमतः पृथक्करण से हल करें।
sequenceDiagram
accTitle: DoEvents से पुनःप्रवेश बग की टाइमलाइन
accDescr: भारी काम के बीच DoEvents कॉल करने से कतार में क्लिक का इवेंट हैंडलर व्यवधान कर चल सकता है, अभी संसाधित डेटा लिख सकता है, और फिर मूल काम फिर शुरू होता है, जिससे समय-निर्भर डेटा दूषण होता है
participant U as UI थ्रेड
U->>U: भारी काम शुरू(डेटा संसाधित हो रहा)
U->>U: DoEvents(कतार संदेश संसाधित करें)
Note over U: बटन-पुनःक्लिक हैंडलर व्यवधान करता है
U->>U: व्यवधान काम डेटा लिखता है
U->>U: मूल काम फिर शुरू(डेटा पहले से असंगत)
चित्र 7: DoEvents “Not Responding” मिटाता है, बदले में मनमाने इवेंट को काम के बीच आमंत्रित कर।
लंबे चलने वाले काम के लिए, डिज़ाइन में प्रगति प्रदर्शन और रद्दीकरण भी शामिल करें। प्रगति IProgress<T> से UI को भेजें और व्यवधान CancellationToken से बताएँ, तो उपयोगकर्ता देख सकता है कि “काम हो रहा है” और जबरन समाप्ति की ओर नहीं जाएगा (जो अक्सर डेटा दूषण का कारण होती है)।
flowchart TB
accTitle: लंबे काम के लिए प्रगति और रद्दीकरण प्रवाह
accDescr: वर्कर थ्रेड प्रगति IProgress से UI थ्रेड को भेजता है; UI पर रद्द क्रिया CancellationToken से वर्कर तक पहुँचती है; वर्कर सुविधाजनक सीमा पर रुकता और साफ़ करता है
w3["वर्कर: लंबा काम"] -->|"IProgress से प्रगति"| ui2["UI: प्रगति और रोक बटन"]
ui2 -->|"CancellationToken"| w3
w3 --> stop2["सीमा पर रुकें और साफ़ करें"]
चित्र 8: प्रगति है “वर्कर → UI”; रद्दीकरण है “UI → वर्कर”। यह पतला द्विदिश चैनल डिज़ाइन में शुरू से शामिल करें।
6. हैंग क्षण की जाँच
“कभी-कभी हैंग होता है” की जाँच में सबसे मूल्यवान चीज़ है ठीक हैंग क्षण की थ्रेड अवस्था। रीबूट करें, और प्रमाण चला जाता है।
डंप लें। Task Manager के Details टैब पर लक्ष्य प्रोसेस पर राइट-क्लिक → “Create dump file”। इतना ही हर थ्रेड के स्टैक वाला पूर्ण डंप देता है। टिकट लेने वाले IT कर्मचारियों से केवल यह कहना कि “जब हैंग हो, बंद करने से पहले यह लें” जाँच की सफलता दर बहुत बदलता है। संग्रह तंत्र बनाने के लिए क्रैश-डंप संग्रह लेख देखें।
UI थ्रेड का स्टैक देखें। डंप WinDbg में खोलें और मैसेज लूप पंप करने वाले थ्रेड (आमतौर पर थ्रेड 0) का स्टैक देखें। सिंक्रोनस I/O ReadFile या नेटवर्क API के रूप में, लॉक प्रतीक्षा WaitFor… परिवार कॉल के रूप में, और थ्रेड पार SendMessage SendMessage के भीतर प्रतीक्षा के रूप में — ज्यों का त्यों दिखता है। पढ़ने का तरीका परिचयात्मक WinDbg लेख में है।
जीवित देखें। Process Explorer से थ्रेड सूची और स्टैक मौके पर जाँच सकते हैं। जब लगातार सुस्त हो, WPR ट्रेस लें और UI थ्रेड की प्रतीक्षाओं का समय के साथ विश्लेषण करें (व्यवहार में WPR/WPA)।
flowchart TB
accTitle: Not Responding जाँच की बुनियादी प्रक्रिया
accDescr: हैंग क्षण पर डंप लें, UI थ्रेड का स्टैक देखें, पहचानें कि सिंक्रोनस I/O, लॉक प्रतीक्षा, या थ्रेड पार SendMessage पर रुका है, और उसे मेल खाते डिज़ाइन सुधार से जोड़ें
hang["हैंग क्षण"] --> dump["डंप लें(बंद करने से पहले)"]
dump --> stack["UI थ्रेड का स्टैक देखें"]
stack --> io["सिंक्रोनस I/O या नेटवर्क प्रतीक्षा"]
stack --> lock["लॉक प्रतीक्षा"]
stack --> sm["थ्रेड पार SendMessage"]
io -.-> fix["साइट को वर्कर पर अलग करें"]
lock -.-> fix
sm -.-> fix
चित्र 9: जाँच का नायक “हैंग क्षण का डंप” है; UI थ्रेड का स्टैक स्वयं कारण का वर्गीकरण है।
लक्षण से पहली कट कैसे लें यह भी मानकीकृत कर सकते हैं। यदि हमेशा विशेष ऑपरेशन पर हैंग हो, पहले उस हैंडलर के भीतर सिंक्रोनस I/O संदेह करें। यदि दुर्लभ हैंग हो और ऑपरेशन से कोई संबंध न हो, लॉक क्रम या थ्रेड पार SendMessage डेडलॉक संदेह करें, और डंप में दोनों थ्रेड के प्रतीक्षा लक्ष्य मिलाएँ। यदि केवल विशेष वातावरण में हैंग हो, नेटवर्क ड्राइव, प्रॉक्सी, या एंटीवायरस जैसे पर्यावरण कारकों से टाइमआउट संदेह करें।
7. सारांश
- “Not Responding” वह तंत्र है जिसमें OS तय करता है कि ऐप ने 5 सेकंड संदेश नहीं लिया और घोस्ट विंडो लगा देता है। प्रदर्शन लगाने वाली चीज़ OS है, ऐप नहीं।
- हैंग का कारण एक बिंदु है: “UI थ्रेड मैसेज लूप पर नहीं लौट सकता”। सिंक्रोनस I/O, नेटवर्क, लॉक प्रतीक्षा, और थ्रेड पार SendMessage क्लासिक हैं।
- उपाय है भारी काम को UI थ्रेड से हटाना। C# में
async/await+Task.Run; Win32 में वर्कर थ्रेड +PostMessage। निष्पादन के दौरान पुनःप्रवेश बटन अक्षम करने जैसे डिज़ाइन से रोकें। DoEventsसे टालना पुनःप्रवेश बग के बदले है।DisableProcessWindowsGhostingकेवल प्रदर्शन हटाता है। कोई भी मूल-कारण सुधार नहीं।- जाँच के लिए “हैंग क्षण” का डंप सबसे महत्त्वपूर्ण है। कारण लगभग हमेशा UI थ्रेड के स्टैक पर ज्यों का त्यों लिखा होता है।
उपयोगकर्ता की दृष्टि से “Not Responding” है “टूट गया”, पर तंत्र जानने पर उसे सटीक वाक्य में अनुवाद कर सकते हैं “UI थ्रेड 5 सेकंड वापस नहीं आया”। उस एक वाक्य से पीछे चलें, तो उम्मीदवार कारण, सुधार, और जाँच प्रक्रिया सब स्वाभाविक निकलते हैं।
संबंधित लेख
- स्प्यूरियस वेकअप — Condition Variable “बिना सूचना के” क्यों जागती है और Windows पर सही प्रतीक्षा
- व्यावहारिक मल्टीथ्रेडिंग सर्वोत्तम अभ्यास: .NET संस्करण — और थ्रेड जोड़ने से पहले क्या तय करें
- COM STA/MTA की बुनियाद — थ्रेडिंग मॉडल और हैंग से बचना
- WinDbg + SOS से क्रैश डंप पढ़ना — संग्रह के बाद विश्लेषण की व्यावहारिक मार्गदर्शिका
- Process Explorer / Handle / VMMap व्यवहार में — हैंग, लीक, और “फ़ाइल उपयोग में” को अभी की अवस्था से पकड़ना
- आपके ऐप की दृष्टि से Windows शटडाउन — निकास सूचनाएँ, रीस्टार्ट, और पावर हानि सही सँभालना
संबंधित परामर्श क्षेत्र
KomuraSoft LLC उन व्यावसायिक ऐप की मूल-कारण जाँच सँभालता है जो “कभी-कभी हैंग” होते हैं या “Not Responding” जाते हैं (डंप विश्लेषण और ट्रेस विश्लेषण), सिंक्रोनस काम से भरे लेगेसी UI कोड को async/await और वर्कर-थ्रेड पृथक्करण में रिफ़ैक्टर करना, तथा न जमने वाले UI डिज़ाइन की समीक्षा। जब पुनरुत्पादन प्रक्रिया अभी न हो, प्रमाण कैसे एकत्र करें उसके डिज़ाइन से मदद शुरू कर सकते हैं।
संदर्भ लिंक
-
Microsoft Learn, IsHungAppWindow function (winuser.h). ऐप को प्रतिक्रिया न देने वाला मानने की कसौटी पर कि वह “इनपुट की प्रतीक्षा न कर रहा हो, स्टार्टअप अनुक्रम में न हो, और 5 सेकंड के आंतरिक टाइमआउट से PeekMessage न बुलाया हो”; इस 5-सेकंड कसौटी के बदल सकने पर; और घोस्ट विंडो के लिए फ़ंक्शन के हमेशा TRUE लौटाने पर। ↩ ↩2
-
Microsoft Learn, GetMessage function (winuser.h). सिस्टम के शीर्ष-स्तरीय विंडो को कुछ सेकंड संदेशों पर प्रतिक्रिया न देने पर प्रतिक्रिया न देने वाली मानकर उसी Z-क्रम, स्थिति, आकार, और रूप की घोस्ट विंडो से बदलने पर; उपयोगकर्ता के केवल खिसकाने, आकार बदलने, या बंद करने पर; और डीबगर जुड़े रहते घोस्ट विंडो न बनने पर। ↩ ↩2 ↩3
-
Microsoft Learn, About Messages and Message Queues. Windows ऐप के इवेंट-चालित होने और विंडो प्रोसीजर के संदेश संसाधित करने पर; कतार संदेश और सीधे भेजे संदेश के भेद पर; प्रतिक्रिया न देने वाली विंडो की घोस्ट विंडो से अदला-बदली पर; और थ्रेड के एक-दूसरे को संदेश भेजने से डेडलॉक कवर करने वाले खंड पर। ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, How to make thread-safe calls to controls (Windows Forms). WinForms कंट्रोल के बनाने वाले के अलावा किसी थ्रेड से छूने के लिए सुरक्षित न होने पर; दूसरे थ्रेड से अपडेट के लिए Invoke/BeginInvoke उपयोग करने पर; और async/await या BackgroundWorker उपयोग करने वाले सुरक्षित असिंक्रोनस पैटर्न पर। ↩ ↩2
-
Microsoft Learn, Using Messages and Message Queues. GetMessage, TranslateMessage, और DispatchMessage वाली विशिष्ट मैसेज-लूप इम्प्लीमेंटेशन पर, और मैसेज कतार जाँचने के तरीके पर। ↩
-
Microsoft Learn, SendMessage function (winuser.h). SendMessage के निर्दिष्ट विंडो की विंडो प्रोसीजर बुलाने और प्रोसेसिंग पूरी होने तक न लौटने पर; दूसरे थ्रेड की विंडो पर भेजने के भेजने वाले को उस थ्रेड के संदेश संसाधित करने तक प्रतीक्षा करवाने पर; और उत्तर की प्रतीक्षा न कर संदेश कतार पर रखने वाले PostMessage से अंतर पर। ↩ ↩2 ↩3
-
Microsoft Learn, DisableProcessWindowsGhosting function (winuser.h). कॉल करने वाले GUI प्रोसेस के लिए घोस्ट-विंडो सुविधा अक्षम कर सकने पर जो प्रतिक्रिया न देने वाली विंडो को न्यूनतम, खिसकाने, और बंद योग्य बनाती है; और अक्षमता के प्रोसेस के जीवन तक रहने पर। ↩
-
Microsoft Learn, SendMessageTimeout function (winuser.h). टाइमआउट के साथ संदेश भेज सकने पर; और फ़्लैग (SMTO_ABORTIFHUNG) पर जो विंडो प्रतिक्रिया न दे (हैंग मानी गई हो) तो प्रतीक्षा किए बिना लौटता है। ↩
संबंधित लेख
निकटवर्ती विषयों में गहराई से जाने के लिए समान टैग वाले नवीनतम लेख।
DllMain और Loader Lock — DLL आरंभीकरण में "कुछ न करें" कहे जाने का वास्तविक कारण
DllMain से LoadLibrary क्यों न बुलाएँ या दूसरे थ्रेड से सिंक्रोनाइज़ न करें। प्राथमिक स्रोतों से यह लेख समझाता है कि लोडर लॉक हर DLL सूचन...
Win32 Thread Pool API — CreateThreadpoolWork से थ्रेड बनाए बिना समवर्तिता
क्या आपके नेटिव कोड में CreateThread कॉल बिखरी पड़ी हैं? यह लेख Vista में पुनर्डिज़ाइन की गई Win32 थ्रेड पूल API — work, timer, wait और i...
स्लीप से रिज़्यूम पर टूटने वाले ऐप — Windows पावर इवेंट कैसे काम करते हैं और उनसे बचने वाले व्यावसायिक ऐप कैसे बनाएँ
लैपटॉप खोला और व्यावसायिक ऐप के कनेक्शन मर चुके थे — कारण वह डिज़ाइन है जिसने स्लीप का हिसाब ही नहीं रखा। यह लेख WM_POWERBROADCAST सूचना ...
स्प्यूरियस वेकअप — Condition Variable "बिना सूचना के" क्यों जागती है और Windows पर सही प्रतीक्षा कैसे करें
कंडीशन वेरिएबल की प्रतीक्षा सूचना आए बिना भी लौट सकती है (स्प्यूरियस वेकअप)। यह लेख Windows इम्प्लीमेंटेशन से समझाता है कि विनिर्देश इसे ...
क्लिपबोर्ड और ड्रैग एंड ड्रॉप कैसे काम करते हैं — व्यावसायिक ऐप में OLE डेटा ट्रांसफ़र सही सँभालना
Excel तालिका चिपकाएँ और फ़ॉर्मेटिंग बिखर जाए; स्रोत ऐप बंद करें और चिपकाना बंद हो जाए — दोनों इसलिए कि क्लिपबोर्ड एक ही सामग्री कई फ़ॉर्म...
संबंधित विषय
ये पृष्ठ विषय को सेवाओं और निर्णयों के व्यापक संदर्भ में रखते हैं।
Windows के तकनीकी विषय
Windows विकास, बग जाँच और मौजूदा संपत्तियों के उपयोग का प्रवेश-द्वार।
UI थ्रेड और टाइमर
WPF / WinForms का UI थ्रेड, असिंक्रोनस प्रवाह, Dispatcher और टाइमर डिज़ाइन।
इस विषय से जुड़ी सेवाएँ
यह लेख निम्नलिखित सेवाओं से सीधे जुड़ा है।
Windows ऐप विकास
व्यावसायिक ऐप, डिवाइस एकीकरण और संचार उपकरण, आवश्यकताओं से विकास तक।
अक्सर पूछे जाने वाले प्रश्न
इस लेख के विषय पर परामर्श में अक्सर पूछे जाने वाले प्रश्न।
- "Not Responding" किन शर्तों पर दिखता है?
- OS विंडो को हैंग तब मानता है जब विंडो वाला ऐप इनपुट की प्रतीक्षा न कर रहा हो, स्टार्टअप अनुक्रम में न हो, और 5 सेकंड से संदेश (PeekMessage) न लिया हो। हैंग शीर्ष-स्तरीय विंडो छिपाई जाती है और उसी स्थिति, आकार, और रूप की "घोस्ट विंडो" से बदली जाती है। "(Not Responding)" टाइटल-बार पाठ और पाले-जैसी सफेदी इसी घोस्ट विंडो की हैं, जो केवल खिसकाने, न्यूनतम करने, या बंद करने देती है। अर्थात् "Not Responding" ऐप स्वयं नहीं दिखाता — यह वह स्क्रीन है जो OS ऐप की ओर से लगाता है।
- क्या काम चलते "Not Responding" न दिखाने की सेटिंग है?
- DisableProcessWindowsGhosting कॉल करने से उस प्रोसेस के लिए घोस्ट विंडो की अदला-बदली अक्षम होती है। वह केवल हैंग को उपयोगकर्ता से कम दृश्य बनाता है — विंडो फिर भी इनपुट पर प्रतिक्रिया नहीं देती, और उपयोगकर्ता की दृष्टि से यह पूर्ण फ्रीज़ है जिसमें खिसकाने या बंद करने का रास्ता नहीं। वास्तविक सुधार प्रदर्शन दबाना नहीं, भारी काम को वर्कर थ्रेड पर ले जाना है ताकि UI थ्रेड पाँच सेकंड तो क्या, दसवें सेकंड भी ब्लॉक न हो। ध्यान दें कि डीबगर जुड़े रहते OS घोस्ट विंडो नहीं बनाता, इसलिए डिबगिंग के दौरान ऐसा लग सकता है मानो "Not Responding" कभी होता ही नहीं।
- क्या DoEvents (मैन्युअल मैसेज लूप पंप) से "Not Responding" बचाना स्वीकार्य है?
- अनुशंसित नहीं। भारी काम के बीच DoEvents या PeekMessage लूप घुमाने से हैंग-विंडो निर्णय टलता है, पर कोई भी इवेंट हैंडलर फिर पुनः-प्रवेश कर सकता है — बटन का दूसरा क्लिक, विंडो बंद करना, टाइमर, आदि। दूसरा हैंडलर अभी संसाधित डेटा लिख दे, या बंद मानी गई फ़ॉर्म छूकर अपवाद फेंके — समय-निर्भर, कठिन-पुनरुत्पादन पुनःप्रवेश बग पैदा होते हैं, जो "Not Responding" से भी बदतर हैं। उचित तरीका है काम स्वयं Task.Run आदि से वर्कर थ्रेड पर ले जाना, और UI थ्रेड को केवल प्रगति प्रदर्शन और रद्दीकरण स्वीकार के लिए छोड़ना।
- वर्कर थ्रेड से UI (कंट्रोल) कैसे अपडेट करूँ?
- WinForms कंट्रोल और WPF एलिमेंट केवल उसी थ्रेड से छूए जा सकते हैं जिसने उन्हें बनाया (सामान्यतः UI थ्रेड)। वर्कर थ्रेड से सीधे छूने से अपवाद या अपरिभाषित व्यवहार होता है। C# में async/await सबसे आसान पथ है: await के बाद निरंतरता कॉल करने वाले UI थ्रेड पर लौटती है, इसलिए await के बाद कंट्रोल सामान्य अपडेट कर सकते हैं। स्पष्ट रूप से बदलने के लिए, WinForms में Control.Invoke/BeginInvoke और WPF में Dispatcher.InvokeAsync उपयोग करें। नेटिव Win32 में स्थापित पैटर्न है वर्कर थ्रेड UI थ्रेड को कस्टम पूर्णता संदेश PostMessage करे, और विंडो प्रोसीजर UI अपडेट करे।
- ऐप के "Not Responding" दिखाने का कारण कैसे जाँचूँ?
- महत्त्वपूर्ण है हैंग के "क्षण स्वयं" की अवस्था पकड़ना। पहले Task Manager के Details टैब से "Create dump file" से पूर्ण डंप लें, फिर WinDbg में UI थ्रेड (मैसेज लूप चलाने वाला थ्रेड) का स्टैक देखें। क्या वह सिंक्रोनस I/O, नेटवर्क प्रतीक्षा, लॉक प्रतीक्षा, या SendMessage से दूसरे थ्रेड की प्रतीक्षा में अटका है — स्टैक पर ज्यों का त्यों दिखता है। जीवित प्रोसेस देखने के लिए Process Explorer की थ्रेड सूची और स्टैक दृश्य उपयोगी हैं; समय के साथ देखने के लिए WPR ट्रेस पकड़ना प्रभावी है। इस साइट का परिचयात्मक WinDbg लेख, व्यवहार में Process Explorer, और व्यवहार में WPR/WPA भी देखें।