Win32 Thread Pool API — CreateThreadpoolWork से thread बनाए बिना concurrency

· अद्यतन तिथि: · · Windows, multithreading, C++, Windows development, Win32 API, performance

संशोधन इतिहास (पहला संस्करण, 22 Aug 2026 को प्रकाशित)
पहला प्रकाशन
इस लेख का हवाला दें(DOI: 10.5281/zenodo.22176807)

यह लेख Zenodo पर संग्रहीत है। नीचे वह DOI है जो हमेशा नवीनतम संस्करण की ओर ले जाता है, और वह DOI भी जो आपके पढ़े जा रहे संस्करण से बँधा है।

Go Komura (2026). Win32 Thread Pool API — CreateThreadpoolWork से thread बनाए बिना concurrency. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22176807 https://comcomponent.com/hi/blog/win32-thread-pool-api/

DOI (नवीनतम संस्करण)
10.5281/zenodo.22176807
DOI (यह संस्करण)
10.5281/zenodo.22176808

“Per client एक CreateThread।” “Timer के लिए एक।” “Event की wait के लिए एक।” — Native Windows code में threads इस तरह फैलते जाते हैं। हर thread stack और kernel object खर्च करता है, और बनाना-destroy करना भी लागत है। काम महीन है, thread भारी — उस mismatch को सोखने के लिए OS जो देता है वह thread pool है।

.NET के ThreadPool और Task.Run की सुविधा जानी-पहचानी है, पर वास्तव में Win32 native में भी अच्छी तरह design की गई, OS-standard thread-pool API है। Windows Vista में व्यापक redesign के बाद, यह API native concurrency की बुनियाद है: work, timer, wait और async I/O unified callback mechanism से सँभाल सकती है। C/C++ में Windows apps, services और DLL लिखने वाले developers के लिए, यह लेख इस API की structure व use, और जिनमें फँसना आसान है उन जालों को, primary sources पर आधारित समझाता है।

1. निष्कर्ष पहले

  • बड़ी संख्या में short-lived काम जारी करने, और केवल-wait threads बदलने के लिए, thread pool अपने CreateThread से बेहतर है। Thread management OS पर छोड़ते हैं और thread संख्या व context switch घटा सकते हैं।1
  • जो use करना चाहिए वह नई API है (CreateThreadpoolWork family)। Vista redesign ने इसे पुरानी API (QueueUserWorkItem family) से सरल, अधिक reliable और high-performance बनाया, और एक process में कई स्वतंत्र pools भी बना सकते हैं।12
  • चार प्रकार के objects हैं। work, जिसमें काम जमा करते हैं; timer, जो समय या अवधि पर चलता है; wait, जो kernel object signal होने पर चलता है; और io, जो async I/O complete होने पर चलता है। सभी एक ही callback mechanism पर सवार हैं।3
  • Shutdown है “wait, फिर close”। चलते callbacks पीछे न छोड़ने का discipline — WaitForThreadpoolWorkCallbacks family से completion की wait, या cleanup group से bulk सँभालना — आवश्यक है।4
  • Callback के अंदर: लंबे समय block न करें (यदि करेंगे, CallbackMayRunLong); उसी pool पर synchronous completion wait न करें; thread की state दूषित न करें। ये तीन iron rules हैं।56
  • DLL से use: unload race से बचें। Explicit shutdown function में completion की wait करें, और FreeLibraryWhenCallbackReturns जैसी dedicated API जानें।3

2. Pool क्यों, और pool कब

Thread pool का विचार सरल है। Per काम thread बनाने के बजाय, OS द्वारा managed worker threads के समूह पर काम (callback) फेंकते हैं। Worker काम एक के बाद एक execute करते हैं, और OS संख्या को load के अनुसार adjust करता है।

Official documentation उन apps के ठोस प्रकार गिनता है जहाँ pool लाभ देता है।1

  • Apps जो बड़ी संख्या में छोटे work items parallel जारी करते हैं (search, network I/O, आदि)
  • Apps जो short-lived threads बार-बार बनाते और तोड़ते हैं
  • Apps जो background में स्वतंत्र काम parallel process करते हैं
  • Apps जो kernel object या event की wait के लिए dedicated threads रखते हैं

अंतिम बिंदु आसानी से छूट जाता है। यदि पाँच threads केवल इसलिए सोते हैं कि “event signal हो तो चलें”, उन्हें pool पर पाँच wait objects से बदला जा सकता है, और wait pool के waiter threads पर एकत्र हो जाती है।

इसके उल्टे, ऐसा काम भी है जो pool के अनुकूल नहीं। जिसे thread priority बदलनी हो, जिसे COM STA चाहिए, जो process के पूरे जीवन चलता रहे — जिस काम को thread पर “personality” चाहिए वह dedicated thread पर रहता है। Worker thread shared resource है; उधार लिया जाता है।

Dedicated thread और pool का चुनावपहले जाँचें कि priority या STA जैसी thread personality चाहिए या नहीं, और क्या लंबे समय चलता है; जो न हो वह short-lived, high-volume या wait-style काम thread pool पर जाता हैहाँनहींहाँनहींPriority या STA जैसी personality?Dedicated thread पर रखेंलंबे समय चलता है?Thread pool पर रखेंShort-lived काम, wait, timer, I/O

चित्र 1: Pool पर केवल वही काम रख सकते हैं जिसे “personality नहीं चाहिए और जो जल्दी खत्म हो”। बाकी पहले की तरह dedicated thread पर रहता है।

इतिहास का एक बिंदु भी पक्का करें। Thread-pool API की दो पीढ़ियाँ हैं। Windows 2000 से चली पुरानी API (QueueUserWorkItem, RegisterWaitForSingleObject आदि), और Vista में व्यापक redesign की नई API (CreateThreadpoolWork family)। नई API worker thread के प्रकार एक करती है, dedicated persistent threads, एक process में कई pools, cleanup group आदि देती है, और official documentation साफ़ कहता है कि यह “सरल, अधिक reliable, बेहतर performance, अधिक flexible” है।1 पुरानी API में “queue में जाने के बाद काम cancel नहीं कर सकते” जैसी structural constraints भी हैं।2 यहाँ से यह लेख केवल नई API सँभालता है।

पुरानी thread-pool API और नई API का मेलपुरानी API का QueueUserWorkItem नई API के work object से, timer queues timer से, registered waits wait से, और BindIoCompletionCallback io से मेल खाते हैंQueueUserWorkItemworkTimer queuestimerRegistered waitswaitBindIoCompletionCallbackio

चित्र 2: पुरानी API से migration target एक-से-एक है। मौजूदा code की सूची इस मेल से शुरू हो सकती है।

3. चार objects — work, timer, wait और io

नई API के केंद्र में चार प्रकार के objects हैं जिनकी callback-चलने की शर्तें अलग हैं।3

Object Create function Callback कब चलता है
work CreateThreadpoolWork SubmitThreadpoolWork से जमा करने पर
timer CreateThreadpoolTimer निर्दिष्ट समय या अवधि आने पर
wait CreateThreadpoolWait Kernel object signal होने पर
io CreateThreadpoolIo जुड़े handle पर async I/O complete होने पर
Thread pool के चार objects और callback mechanismwork स्पष्ट जमा पर चलता है, timer समय पर, wait kernel-object signal पर, और io async I/O completion पर; सभी एक ही worker thread समूह पर callback के रूप में चलते हैंकौन सा object?work(जमा पर)Timer, wait, या io?timer(समय / अवधि)Wait या io?wait(signal पर)io(I/O completion)Worker callbacks चलाते हैं

चित्र 3: चलने की शर्तें अलग हैं, पर चारों इस mechanism में एक हैं कि “उसी pool के workers callbacks चलाते हैं”।

यह एकीकरण practical शक्ति है। Periodic processing, event प्रतिक्रिया और I/O-completion processing प्रत्येक को dedicated thread पर लिखने के बजाय, उन्हें एक callback style पर संरेखित कर सकते हैं। Timers पूरे pool की एक timer queue में एकत्र होते हैं, और wait थोड़े waiter threads पर एकत्र होती है — process से “केवल सोने वाले” threads गायब हो जाते हैं।1

केवल-wait threads को wait object से बदलनापहले per event सोने वाले केवल-wait threads wait objects बन जाते हैं और pool के waiter threads पर एकत्र होते हैं, इसलिए callback केवल signal होने पर चलता है5 dedicated waiter threads अलग सोते5 stacks और 5 threads खर्च5 wait objectsPool के waiter threads पर एकत्रCallback केवल signal पर

चित्र 4: “केवल सोकर wait” वाले threads wait objects बनाकर हटाए जा सकते हैं। Pool migration की यह स्पष्ट पहली चाल है।

4. बुनियादी pattern — work object से एक पूरा चक्कर

सबसे अधिक use होने वाले work object से शिष्टाचार एक बार चलते हैं।4

VOID CALLBACK WorkCallback(PTP_CALLBACK_INSTANCE instance,
                           PVOID context, PTP_WORK work)
{
    // The context is fixed at creation time. Per-item data is passed through a synchronised queue
    WORK_QUEUE* queue = (WORK_QUEUE*)context;
    ITEM* item = Dequeue(queue);        // Take one item under exclusive control
    ProcessItem(item);
}

// 1) Create (bind the callback to the shared context = the queue)
PTP_WORK work = CreateThreadpoolWork(WorkCallback, &queue, NULL);
if (!work) { /* Failure handling with GetLastError */ }

// 2) Submit once for each item you enqueue (keep the item count and the submit count in step)
Enqueue(&queue, item);
SubmitThreadpoolWork(work);

// 3) Stop the submitter, then wait for completion (TRUE also attempts to cancel work that has not yet started)
WaitForThreadpoolWorkCallbacks(work, FALSE);

// 4) Close
CloseThreadpoolWork(work);

दो बिंदु पकड़ें। पहला, एक ही work object पर SubmitThreadpoolWork एक से अधिक बार कर सकते हैं। हर जमा callback चलाता है (parallel)।7 पर callback को दिया गया context create time पर तय होता है, इसलिए एक work object से “एक ही तरह के काम की N वस्तुएँ” लिखते समय, ऊपर के code की तरह context में synchronized queue रखें और per जमा एक वस्तु लें (per वस्तु work object बनाने वाला design भी ठीक है)। दूसरा, बंद करने से पहले हमेशा completion की wait करें। चलते या queued callbacks रहते object बंद करना, या callback जिस memory का reference ले उसे free करना, ज्यों का त्यों use-after-free है। इस wait को सुरक्षित close बनाने के लिए पहले submitter रोकना prerequisite है — ऐसी structure में जहाँ दूसरा thread wait के parallel अभी Submit कर सकता हो, wait के बाद का जमा Close से race करता है। WaitForThreadpoolWorkCallbacks का दूसरा argument TRUE देने से अभी start न हुए जमा cancel करने का प्रयास भी होता है।

Work object का lifecycleCreateThreadpoolWork से बनाएँ; SubmitThreadpoolWork से जमा करें और callbacks parallel चलें। Shutdown पर पहले नए जमा रोकें, WaitForThreadpoolWorkCallbacks से हर callback की completion की wait करें, फिर CloseThreadpoolWork से बंद करेंCreateThreadpoolWork से बनाएँSubmitThreadpoolWork से जमा(दोहराया जा सकता)Callbacks parallel चलते हैंनए जमा रोकेंWaitForThreadpoolWorkCallbacks से waitCloseThreadpoolWork से बंद करें

चित्र 5: Shutdown order है “जमा रोकें → completion की wait → close”। कोई छोड़ें तो use-after-free या race मिलती है।

Default पर callbacks process-default pool पर चलते हैं। कई uses के लिए वह पर्याप्त है। अगला अध्याय तब है जब pool बाँटना चाहें।

5. Custom pool और cleanup group

Pool बाँटें। CreateThreadpool से स्वतंत्र pool बना सकते हैं और SetThreadpoolThreadMaximum / SetThreadpoolThreadMinimum से thread संख्या की ऊपरी व निचली सीमा set कर सकते हैं।8 Typical use isolation है। ताकि “धीमा हो सकने वाला batch-जैसा काम” “तुरंत प्रतिक्रिया चाहिए वाले काम” के workers न खा जाए, pool बाँटें और प्रत्येक को अपना thread budget दें।

Callback environment से बाँधें। काम किस pool पर चले यह TP_CALLBACK_ENVIRON (callback environment) initialize कर, SetThreadpoolCallbackPool से pool की ओर इंगित कर, और उसे CreateThreadpoolWork आदि के तीसरे argument के रूप में देकर specify होता है।9

Cleanup group से मोड़ें। कई objects बनाने वाले module में shutdown processing “सभी की wait, सभी close” का पाठ बन जाती है। यदि CreateThreadpoolCleanupGroup से group बनाएँ और callback environment से हर object उससे जोड़ें, तो एक CloseThreadpoolCleanupGroupMembers हर member object की completion-wait और release एक साथ करता है।34

Callback environment से configuration बाँधनाCallback environment custom pool और cleanup group की ओर इंगित करता है; उस environment से बने work और timer उसी pool पर चलते हैं, और cleanup group पर bulk operation completion-wait व release एकत्र करता हैCallback environment(TP_CALLBACK_ENVIRON)Custom pool(thread संख्या नियंत्रण)Cleanup groupwork / timer / wait / io बनाते समयएक झटके में wait और release

चित्र 6: Callback environment वह mechanism है जो object-create time पर “किस pool पर चले, और कौन साफ़ करे” inject करता है।

6. जाल — callback के अंदर discipline

लगभग हर thread-pool bug “उधार thread पर मनमानी करने” से आता है।

लंबे समय block करना। Pool thread संख्या इस धारणा पर adjust करता है कि callbacks तुरंत return करें। Default पर लंबा काम या लंबी wait अन्य callbacks के execution में delay करती है। लंबे चल सकने वाले callback को CallbackMayRunLong से “यह लंबा चलेगा” घोषित करना चाहिए (pool इसे thread जोड़ने का संकेत मानता है), या पहले से dedicated thread पर भेजना चाहिए। ध्यान दें कि CallbackMayRunLong FALSE लौटाता है जब अन्य callbacks के लिए worker तैयार नहीं कर सकता। Return value जाँचे बिना block करते रहें तो pool फिर भी जाम होता है, इसलिए FALSE हो तो उस पक्ष पर जाएँ जो block न करे — काम बाँटें, dedicated thread पर भेजें, आदि।5

उसी pool पर synchronous completion wait। ऐसा रूप जहाँ callback A के अंदर उसी pool पर जमा काम B की completion की WaitForThreadpoolWorkCallbacks आदि से wait हो, उस क्षण pool-starvation deadlock बन जाता है जब हर worker “दूसरे worker की wait” में हो। कामों के बीच dependency को wait नहीं, बल्कि “B के completion callback से अगला जमा करें” जैसी continuation के रूप में लिखें।

Pool-starvation deadlock की structureयदि हर worker thread उसी pool पर जमा अन्य काम की completion की synchronous wait करे, तो उस काम को चलाने के लिए खाली worker नहीं बचता, और सब सदा wait करते रहते हैंWorker 1: काम X की waitकाम X और Y चलने की waitWorker 2: काम Y की waitउन्हें चलाने को खाली worker नहींसब सदा wait(starvation deadlock)

चित्र 7: यदि worker के अंदर से worker की synchronous wait करें, तो waited काम चलाने वाला कोई नहीं बचता।

Thread की state दूषित करना। Worker thread अगले callback के लिए reuse होता है। Thread priority बदलना, COM initialization state, TLS में छोड़ा मान, छोड़ना भूल गया lock — इनमें से कोई भी अगले (असंबंधित) callback का दूषण बनता है। “Pool पर फेंकी गई function thread की personality पर depend न हो” पुरानी-API काल से official सावधानी है।6 Cleanup के dedicated mechanisms हैं; उदाहरण के लिए, LeaveCriticalSectionWhenCallbackReturns pool से कह सकता है कि “यह callback return करे तो यह lock छोड़ दें”।3

DLL unload से race। Callback चलते code वाला DLL unload हो तो access violation होता है। बुनियादी रूप है DLL की shutdown function में completion की पूरी wait; FreeLibraryWhenCallbackReturns उस स्थिति के लिए है “यह callback अंतिम काम है, और पूरा होने पर मैं खुद सहित DLL free करना चाहता हूँ”। पर यह API केवल “चलते callback के return पर एक reference छोड़ती है”; callback start होने से पहले unload नहीं रोकती। इसे जोड़ के रूप में use करें: जमा से पहले GetModuleHandleEx से अपना module reference लें, और callback उस reference को इस API से छोड़े।3 और यह completion-wait DllMain के अंदर न करें — “DllMain और Loader Lock” में कहा गया है, DllMain के अंदर दूसरे thread की wait deadlock pattern है।

DLL unload और callback की race की तैयारीCallback चलते DLL unload access violation बनता है, इसलिए बुनियादी रूप explicit shutdown function में completion की wait कर फिर close करना है; जब अंतिम callback खुद DLL free करे, FreeLibraryWhenCallbackReturns use करेंCallback के दौरान unloadAccess violationWait, फिर closeसुरक्षित unloadShutdown function मेंFreeLibraryWhenCallbackReturnsअंतिम callback DLL free करेDllMain के अंदर नहीं

चित्र 8: बुनियादी रूप explicit shutdown function में “wait, फिर close” करना है। DllMain के अंदर wait अलग deadlock बुलाती है।

जमा काम के अंदर exception और crash। Worker thread पर unhandled exception process साथ ले जाता है। Dedicated thread की thread function की तरह, callback के प्रवेश पर exception व्यापक रूप से पकड़ने और log करने की नीति लागू करें।

7. Standard library और .NET से संबंध — किस परत पर लिखें

अंत में, अन्य tools से यह कहाँ बैठता है यह छाँटते हैं।

  • यदि C++ std::async / std::thread पर्याप्त हों, वे पहला उम्मीदवार हैं। वे portable हैं, code छोटा है, और future के अर्थ भी standard तय करते हैं।10
  • Win32 thread pool सीधे use करने के कारण तब हैं जब आप (1) timer, wait और io सहित unified callback mechanism चाहते हैं, (2) pool विभाजन या thread-संख्या नियंत्रण चाहते हैं, या (3) DLL या COM component के अंदर अपने threads नहीं रखना चाहते।
  • .NET पक्ष पर, ThreadPool और Task वही भूमिका निभाते हैं, और I/O completion IOCP से बँधी है। यह तहखाने की structure “IOCP और .NET Thread Pool” में समझाई गई है।
किस परत के tools से लिखें यह तय करनायदि standard C++ async या thread पर्याप्त हों तो वे use करें; Win32 thread pool सीधे तब जब timer, wait और I/O completion का एकीकरण, pool विभाजन या thread-संख्या नियंत्रण चाहिए, या DLL या COM में अपने threads न चाहेंहाँनहींtimer, wait और io का एकीकरणPool विभाजन / संख्या नियंत्रणDLL में अपने threads से बचनाStandard C++ tools पर्याप्त?std::async / std::threadक्या चाहिए?Win32 thread pool

चित्र 9: संदेह हो तो standard library से शुरू करें; इस API की बारी तब आती है जब वह जो व्यक्त न कर सके वह requirement आए।

यानी, यह API concurrency की बुनियाद उस बिंदु पर है जब आपने “native लिखना” तय कर लिया हो। Realistic cleanup चरणबद्ध है: अपने CreateThread के फैलाव से migration target के रूप में, पहले work object लाएँ, फिर केवल-wait threads को wait और timer threads को timer से बदलें।

8. सारांश

  • बड़ी संख्या में short-lived काम जारी करने, और केवल-wait व केवल-timer threads साफ़ करने के लिए, अपने threads के बजाय OS-standard thread pool। Use Vista के बाद की नई API है।
  • केंद्र में चार objects work, timer, wait और io हैं। चलने की शर्तें अलग; वे एक ही worker समूह और एक ही callback style पर एक हैं।
  • शिष्टाचार है “बनाएँ → जमा करें → completion की wait → close”। कई जमा parallel चलते हैं। Cleanup group shutdown processing bulk कर सकता है।
  • Callback के तीन iron rules: लंबे समय block न करें (यदि करेंगे, CallbackMayRunLong); उसी pool पर synchronous wait न करें; thread की state दूषित न करें।
  • DLL से use: unload race से बचें। Explicit shutdown function में completion की wait करें; DllMain में न करें।
  • जहाँ standard C++ या .NET पर्याप्त हों, वे use करें। इस API की बारी तब है जब timer/wait/io का एकीकरण या pool नियंत्रण चाहिए।

Thread-pool API, Win32 API में, नई और बेहतर-design वाली ओर है। “Thread बनाने” के विचार से “callback फेंकने” के विचार तक स्थानांतरण पूरा होने पर, native code में concurrency काफी साफ़ लिखी जाती है।

संबंधित लेख

संबंधित परामर्श क्षेत्र

KomuraSoft LLC उन native code से thread pool पर migration design सँभालता है जिनके threads फैल गए हैं, C++ apps और DLL में concurrent processing की design review, और pool starvation या callback से आए hang व crash की root-cause जाँच। मौजूदा code की सूची से परामर्श स्वागत योग्य है।

संदर्भ लिंक

  1. Microsoft Learn, Thread Pools. Thread pool worker threads का संग्रह होने पर जो app की ओर से async callbacks दक्षता से execute करता है; जिन app प्रकारों के अनुकूल है (बड़ी संख्या में छोटे work items parallel जारी करना, short-lived threads बार-बार बनाना-तोड़ना, स्वतंत्र काम parallel process करना, kernel object पर विशेष wait, आदि); और व्यापक Vista redesign (worker-thread प्रकारों का एकीकरण, एक timer queue, dedicated persistent threads, cleanup group, एक process में कई pools, और नई API) पर। ↩ ↩2 ↩3 ↩4 ↩5

  2. Microsoft Learn, Thread Pooling. पुरानी thread-pool API की structure पर (QueueUserWorkItem, timer queues, registered waits, BindIoCompletionCallback); queue में जाने के बाद काम cancel करने का तरीका न होने पर; और Vista में आई नई thread-pool API के सरल तथा reliability, performance व flexibility में श्रेष्ठ बताए जाने पर। ↩ ↩2

  3. Microsoft Learn, threadpoolapiset.h header. चार object-create functions CreateThreadpoolWork, CreateThreadpoolTimer, CreateThreadpoolWait और CreateThreadpoolIo सहित function list पर; cleanup group (CreateThreadpoolCleanupGroup); और callback completion से बँधे cleanup (LeaveCriticalSectionWhenCallbackReturns, FreeLibraryWhenCallbackReturns, आदि) पर। ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  4. Microsoft Learn, Using the Thread Pool Functions. CreateThreadpoolWork से बनाने, SubmitThreadpoolWork से जमा करने, WaitForThreadpoolWorkCallbacks से completion की wait, और CloseThreadpoolWork से बंद करने की बुनियादी प्रक्रिया पर; और custom pool को callback environment व cleanup group से जोड़ने वाले configuration उदाहरण पर। ↩ ↩2 ↩3

  5. Microsoft Learn, CallbackMayRunLong function (threadpoolapiset.h). Pool को सूचित करने पर कि वर्तमान callback लंबे समय चल सकता है, ताकि pool अन्य callbacks के लिए thread सुरक्षित करने का निर्णय ले सके; और जहाँ संभव हो लंबे-चलने वाले callbacks के लिए dedicated thread पर विचार करने पर। ↩ ↩2

  6. Microsoft Learn, Thread Pooling. Thread pool पर जमा work items, और वे जिन functions को call करते हैं, के thread-pool safe होने पर; execution thread को dedicated persistent thread न मानने पर; और TLS तथा persistent thread चाहिए वाली async calls से बचने पर। ↩ ↩2

  7. Microsoft Learn, SubmitThreadpoolWork function (threadpoolapiset.h). एक ही work object को पूर्ववर्ती callback की completion की wait किए बिना एक से अधिक बार जमा कर सकने पर, जिससे callbacks parallel चलें; और pool के दक्षता के लिए thread संख्या adjust (throttle) कर सकने पर। ↩

  8. Microsoft Learn, SetThreadpoolThreadMaximum function (threadpoolapiset.h). CreateThreadpool से बने pool की worker-thread संख्या पर ऊपरी सीमा set कर सकने पर (निचली सीमा SetThreadpoolThreadMinimum है)। ↩

  9. Microsoft Learn, CreateThreadpoolWork function (threadpoolapiset.h). Callback function और context pointer से work object बनाने पर; और तीसरे argument TP_CALLBACK_ENVIRON के callback का execution environment (संबंधित pool आदि) specify कर सकने पर, NULL का अर्थ default environment में चलना। ↩

  10. Microsoft Learn, <future>. std::async और future के माध्यम से per कार्य async execution standard library के रूप में दिए जाने पर, ताकि threads सीधे manage किए बिना concurrency लिख सकें। ↩

निकटवर्ती विषयों में गहराई से जाने के लिए समान टैग वाले नवीनतम लेख।

"Not Responding" वास्तव में क्या है — Windows ऐप के hang का फैसला कैसे करता है, और hang न करने वाले ऐप कैसे design करें

Windows का "Not Responding" वह mechanism है जिसमें OS तय करता है कि window ने 5 सेकंड message नहीं लिया और उसे ghost window से बदल देता ह...

ये पृष्ठ विषय को सेवाओं और निर्णयों के व्यापक संदर्भ में रखते हैं।

यह लेख निम्नलिखित सेवाओं से सीधे जुड़ा है।

अक्सर पूछे जाने वाले प्रश्न

इस लेख के विषय पर परामर्श में अक्सर पूछे जाने वाले प्रश्न।

CreateThread से अपने threads बनाने की तुलना में thread pool बेहतर क्यों है?
जब बड़ी संख्या में short-lived काम हों तो दक्षता, और thread-management code में कमी। Thread बनाना और destroy करना अनदेखा न करने योग्य लागत है, इसलिए जो app "हर काम के लिए CreateThread और पूरा होने पर destroy" दोहराता है, या केवल event की wait में सोने वाले कई threads रखता है, वह pool पर जाने से thread संख्या और context switch घटा सकता है। Official documentation pool उम्मीदवारों में उन apps को गिनता है जो बड़ी संख्या में छोटे work items parallel जारी करते हैं, जो कई short-lived threads बनाते हैं, और जिनके threads केवल kernel object की wait के लिए dedicated हैं। इसके उल्टे, वह काम जिसे "thread पर अपनी personality चाहिए" — priority बदलना, COM STA, लंबे समय चलने वाली dedicated processing — पहले की तरह dedicated thread पर ही रखना चाहिए।
QueueUserWorkItem जैसी पुरानी thread-pool functions से यह कैसे अलग है?
Thread pool Windows Vista में व्यापक रूप से redesign हुआ। वर्तमान threadpoolapiset-family API (CreateThreadpoolWork आदि) नई API हैं; QueueUserWorkItem, RegisterWaitForSingleObject आदि पुरानी (legacy) API हैं। नई API worker thread के प्रकार एक करती है, एक process में कई स्वतंत्र pools बनाने देती है, और cleanup group से bulk release तथा callback completion से बँधे lock release या DLL unload जैसे mechanisms देती है। Official documentation यह भी कहता है कि नई API सरल है और reliability, performance व flexibility में श्रेष्ठ है। पुरानी API में structural constraints भी हैं, जैसे "queue में जाने के बाद काम cancel करने का कोई तरीका नहीं", इसलिए नए code में नई API use करें।
Callback के अंदर ऐसी बातें हैं जो नहीं करनी चाहिए?
तीन बड़ी हैं। पहली, default पर लंबे समय block करना या लंबा काम करना। Pool thread संख्या इस धारणा पर adjust करता है कि callbacks तुरंत पूरे हों, इसलिए लंबे काम के लिए या तो CallbackMayRunLong से घोषित करें या dedicated thread use करें। दूसरी, उसी pool पर जमा किए अन्य काम की completion की synchronous wait। यदि हर worker "दूसरे worker की wait" में फँस जाए, तो pool-starvation deadlock होता है। तीसरी, thread की personality पर dependency। Worker threads callbacks के बीच shared होते हैं, इसलिए बदली thread priority या COM initialization state लेकर लौटना, या TLS में state छोड़ना, अगले callback को दूषित करता है। अंत में cleanup (lock छोड़ना या DLL unload) के लिए LeaveCriticalSectionWhenCallbackReturns और FreeLibraryWhenCallbackReturns जैसे dedicated mechanisms हैं।
DLL से thread pool use करते समय क्या ध्यान रखें?
सबसे बड़ा खतरा है "callback अभी चल रहा हो और DLL unload हो जाए"। Unload के बाद callback चले तो access violation होता है। DLL पक्ष को shutdown processing में अपने जारी callbacks की completion की विश्वसनीय wait करनी चाहिए — WaitForThreadpoolWorkCallbacks जैसी wait function से, या cleanup group पर CloseThreadpoolCleanupGroupMembers से — और तभी object बंद करें। पर DllMain के अंदर यह wait loader lock से interact कर deadlock कर सकती है, इसलिए नियम है इसे DllMain में नहीं, explicit shutdown function में करना। उस स्थिति के लिए जब callback खुद DLL free करना चाहे क्योंकि "यह काम अंतिम है", dedicated API FreeLibraryWhenCallbackReturns दी गई है।
अब C++ std::async और .NET का ThreadPool होने पर भी इस API को सीधे use करने के अवसर हैं?
हाँ। कसौटी है "क्या उस परत का tool पर्याप्त है"। यदि C++ में चाहिए concurrency की granularity std::async या std::thread से ढक जाए, तो portability की दृष्टि से भी standard library पहला उम्मीदवार है। दूसरी ओर, timer, kernel-object wait और async I/O completion को एक callback mechanism में एक करना; काम के प्रकार के अनुसार pool बाँटना और thread संख्या नियंत्रित करना; DLL या COM component के अंदर अपने threads न रखना — ये requirements Win32 thread pool पूरा करता है। .NET के ThreadPool और IOCP से संबंध संबंधित लेख में है, और जब तक native लिख रहे हैं, नीचे की परत पर बैठा यह mechanism जानना व्यर्थ नहीं।

लेखक की प्रोफ़ाइल

लेख के लेखक का परिचय पृष्ठ।

Go Komura

KomuraSoft LLC के प्रतिनिधि

Windows सॉफ़्टवेयर विकास, तकनीकी परामर्श और बग जाँच में विशेषज्ञ, विशेष रूप से मौजूदा सिस्टम वाली परियोजनाओं और पुनरुत्पादन में कठिन बग में।

सार्वजनिक लिंक

ब्लॉग पर लौटें