विंडोज थ्रेडिंग: _beginthread vs _beginthreadex vs CreateThread C ++


133

एक धागा शुरू करने का एक बेहतर तरीका क्या है _beginthread, _beginthreadxया CreateThread?

मैं निर्धारित करने के लिए क्या करने के फायदे / नुकसान कर रहे हैं कोशिश कर रहा हूँ _beginthread, _beginthreadexऔर CreateThread। ये सभी फ़ंक्शन एक नए बनाए गए थ्रेड पर थ्रेड हैंडल लौटाते हैं, मुझे पहले से ही पता है कि CreateThread थोड़ी अतिरिक्त जानकारी प्रदान करता है जब कोई त्रुटि होती है (इसे कॉल करके चेक किया जा सकता है GetLastError) ... लेकिन कुछ चीजें जो मुझे विचार करनी चाहिए, जब मैं ' इन कार्यों का उपयोग कर रहा हूँ?

मैं एक विंडोज़ एप्लिकेशन के साथ काम कर रहा हूं, इसलिए क्रॉस-प्लेटफॉर्म संगतता पहले से ही प्रश्न से बाहर है।

मैं msdn प्रलेखन के माध्यम से चला गया हूं और मैं अभी समझ नहीं पा रहा हूं, उदाहरण के लिए, कोई भी CreateThread या इसके विपरीत _beginthread का उपयोग करने का निर्णय क्यों लेगा।

चीयर्स!

अद्यतन: ठीक है, सभी जानकारी के लिए धन्यवाद, मैं भी स्थानों के एक जोड़े में पढ़ा है कि मैं फोन नहीं कर सकते हैं WaitForSingleObject()अगर मैं इस्तेमाल किया _beginthread(), लेकिन अगर मैं फोन _endthread()सूत्र में काम है कि नहीं होना चाहिए? वहाँ क्या सौदा है?


2
यहाँ एक विश्लेषण है कि _beginthreadex () C / C ++ प्रोग्रामर के लिए क्या करता है जो मुझे एली बेंडरस्की की वेबसाइट पर एक लिंक से मिला। यह CreateThread () का उपयोग करना है या नहीं, इस पर प्रश्नोत्तर से है। microsoft.com/msj/0799/win32/win320799.aspx
रिचर्ड चैम्बर्स

जवाबों:


96

CreateThread() कर्नेल स्तर पर नियंत्रण का एक और धागा बनाने के लिए एक कच्चा Win32 एपीआई कॉल है।

_beginthread()& _beginthreadex()C रनटाइम लाइब्रेरी कॉल हैं जो CreateThread()पर्दे के पीछे से कॉल करते हैं। एक बार CreateThread()वापस आ _beginthread/ex()जाने के बाद, सी रनटाइम लाइब्रेरी को नए धागे में प्रयोग करने योग्य और सुसंगत बनाने के लिए अतिरिक्त बहीखाता पद्धति का ध्यान रखा जाता है।

C ++ में आपको लगभग निश्चित रूप से उपयोग करना चाहिए _beginthreadex()जब तक कि आप C रनटाइम लाइब्रेरी से बिल्कुल भी कनेक्ट नहीं होंगे (उर्फ MSVCRT * .dll / .lib)।


39
यह अब उतना सच नहीं है जितना पहले हुआ करता था। CRT CreateThread () द्वारा बनाए गए थ्रेड में सही ढंग से कार्य करेगा जो कि वह सिग्नल () फ़ंक्शन के अपवाद के साथ है। CreateThread () के साथ बनाए गए प्रत्येक थ्रेड के लिए एक छोटी मेमोरी लीक (~ 80 बाइट्स) होगी जो CRT का उपयोग करती है, लेकिन यह सही ढंग से कार्य करेगी। अधिक जानकारी के लिए देखें: support.microsoft.com/default.aspx/kb/104641
जॉन डाइब्लिंग

1
@ जॉन: वास्तव में यह बग केवल MSVC ++ 6.0
bobobobo

5
@ बोबोबोबो: अच्छा सवाल। मैं केवल अनुमान लगा सकता हूं कि एमएस मूल रूप से _beginदिनचर्या को आंतरिक कॉल करने का इरादा रखता CreateThreadथा और माना जाता था कि एपीआई फ़ंक्शन हर किसी को कॉल करेगा। एक अन्य संभावित व्याख्या यह है कि मानक को अनदेखा करने और चीजों के नामकरण के बारे में बहुत खराब निर्णय लेने का एमएस का एक लंबा और शानदार इतिहास है।
जॉन डिब्लिंग

15
_beginकार्यों अंडरस्कोर से प्रारंभ क्योंकि माइक्रोसॉफ्ट और अधिक बारीकी से मानक का पालन करने के लिए शुरू कर दिया। सी रनटाइम में, अंडरस्कोर के साथ होने वाले नाम कार्यान्वयन के लिए आरक्षित हैं (और कार्यान्वयन उन्हें अंत-उपयोगकर्ता के उपयोग के लिए दस्तावेज कर सकता है, इन के साथ)। beginthreadex()एक ऐसा नाम है जिसे उपयोगकर्ता उपयोग करने के लिए अनुमति देता है। यदि सी रनटाइम ने इसका उपयोग किया है, तो यह एंड-यूज़र प्रतीक के साथ संघर्ष कर सकता है जो उपयोगकर्ता के पास वैध अधिकार था जो उपयोग करने की उम्मीद करने में सक्षम हो। ध्यान दें कि Win32 API सी रनटाइम का हिस्सा नहीं है, और वे उपयोगकर्ता के नाम स्थान का उपयोग करते हैं।
माइकल बूर

2
@Lothar: वहाँ रहे हैं Win32 API कॉल के बीच मतभेद CreateThreadऔर CRT कॉल _beginthread/ex, और जब एक धागे पर सीआरटी बुला, यह हमेशा के साथ बनाया जाना चाहिए _beginthread/ex। यदि आप नहीं करते हैं, तो स्मृति रिसाव नहीं हो सकता है। CreateThreadउदाहरण के लिए, जब आप कॉल करते हैं , तो आप निश्चित रूप से अपने फ़्लोटिंग पॉइंट वातावरण को ठीक से आरंभ नहीं कर पाएंगे । नहीं है और अधिक : "एक धागे का उपयोग कर बनाई हैं CreateThread सीआरटी कहता है, सीआरटी कम स्मृति की स्थिति में इस प्रक्रिया को समाप्त कर सकता है।"
IInspectable

37

_beginthread()और इसके बीच कई अंतर हैं _beginthreadex()_beginthreadex()अधिक कार्य करने के लिए बनाया गया था CreateThread()(दोनों मापदंडों में और यह कैसे व्यवहार करता है)।

जैसा कि ड्रयू हॉल का उल्लेख है, यदि आप C / C ++ रनटाइम का उपयोग कर रहे हैं, तो आपको उपयोग करना चाहिए _beginthread()/ _beginthreadex()इसके बजाय CreateThread()ताकि रनटाइम को स्वयं थ्रेड इनिशियलाइज़ेशन (थ्रेड स्थानीय संग्रहण, आदि की स्थापना) करने का मौका मिले।

व्यवहार में, इसका मतलब है कि CreateThread()बहुत अधिक कभी भी सीधे आपके कोड द्वारा उपयोग नहीं किया जाना चाहिए।

मतभेदों पर MSDN दस्तावेज़ों के लिए _beginthread()/ _beginthreadex()में काफी विस्तार है - एक और महत्वपूर्ण बात यह है कि चूंकि _beginthread()थ्रेड से बाहर निकलने पर थ्रेड के लिए थ्रेड हैंडल स्वचालित रूप से बंद हो जाता है, जब थ्रेड बाहर निकलता है, तो _beginthread द्वारा उत्पन्न थ्रेड जल्दी से, _beginthread के कॉल करने के लिए दिया गया हैंडल अमान्य या खराब हो सकता है, दूसरे धागे पर इंगित करें "।

यहाँ _beginthreadex()सीआरटी स्रोत में टिप्पणियों के लिए क्या कहना है:

Differences between _beginthread/_endthread and the "ex" versions:

1)  _beginthreadex takes the 3 extra parameters to CreateThread
  which are lacking in _beginthread():
    A) security descriptor for the new thread
    B) initial thread state (running/asleep)
    C) pointer to return ID of newly created thread

2)  The routine passed to _beginthread() must be __cdecl and has
  no return code, but the routine passed to _beginthreadex()
  must be __stdcall and returns a thread exit code.  _endthread
  likewise takes no parameter and calls ExitThread() with a
  parameter of zero, but _endthreadex() takes a parameter as
  thread exit code.

3)  _endthread implicitly closes the handle to the thread, but
  _endthreadex does not!

4)  _beginthread returns -1 for failure, _beginthreadex returns
  0 for failure (just like CreateThread).

अद्यतन जनवरी 2013:

वीएस 2012 के लिए सीआरटी में प्रदर्शन का एक अतिरिक्त बिट है _beginthreadex(): यदि प्रक्रिया एक "पैक ऐप" है (यदि कुछ उपयोगी उपयोगी है GetCurrentPackageId()) तो रनटाइम नए बनाए गए धागे पर एमटीए को इनिशियलाइज़ करेगा।


3
वहाँ रहे हैं उचित समय जब CreateThread () न्यायसंगत न हो, लेकिन ईमानदारी से आप वास्तव में यह करने के लिए अपने रास्ते से बाहर जाना है। हम कुछ भी पोर्टेबल की पूरी कमी की बात कर रहे हैं और एक विशेष रूप से Win32 API DLL या App लिख रहे हैं। जिसमें सी-रनटाइम कॉल नहीं है। यहां तक ​​कि एसटीएल का उपयोग सीमित है जिसमें आपको Win32 मेमोरी प्रबंधन फ़ंक्शन का उपयोग करने के लिए कस्टम आवंटन प्रदान करना होगा। डेवलपर स्टूडियो के साथ ऐसा करने के लिए सेटअप अपने आप में एक काम है, लेकिन सबसे छोटे संभव फुटप्रिंट के साथ एकमात्र-WIN32 के लिए, यह किया जा सकता है। लेकिन हाँ, यह लगभग सभी के लिए खूनी संभावना नहीं है, लेकिन बहुत कुछ चुनिंदा है।
WhozCraig

1
@HozCraig: CRT को छोड़ते समय अधिक गंभीर सीमाएँ हैं। सबसे प्रमुख हैं: कोई 64-बिट पूर्णांक समर्थन, कोई फ़्लोटिंग बिंदु समर्थन, और - सबसे अधिक - कोई अपवाद हैंडलिंग नहीं। इसका वास्तव में कोई अपवाद नहीं है । एसईएच अपवाद भी नहीं। यह बनाने के लिए विशेष रूप से कठिन है, और CreateThreadराइट थिंग होने की संभावना कम होने की संभावना है ।
IInspectable

@MichaelBurr: आप VC ++ 2015 के लिए अपने उत्तर को अपडेट करना चाह सकते हैं ।
user541686

@ मेहरदाद: विशेष रूप से किन बदलावों का उल्लेख करने लायक है?
IInspectable

मैंने पाया है कि CreateThread के साथ बनाए गए थ्रेड्स पर DisableThreadLibraryCalls का कोई प्रभाव नहीं है, लेकिन _beginthread या _beginthreadex के साथ बनाए गए थ्रेड्स को अक्षम करता है।
SPlatten 11

23

सामान्य तौर पर, कॉल _beginthread()/_endthread()(या ex()वेरिएंट) करने के लिए सही काम करना है । हालांकि, अगर आप एक .dll के रूप में सीआरटी का उपयोग करें, सीआरटी राज्य ठीक से प्रारंभ हो जाएगा और CRT के रूप में नष्ट कर दिया DllMainसाथ बुलाया जाएगा DLL_THREAD_ATTACHऔर DLL_THREAD_DETACHजब बुला CreateThread()और ExitThread()या लौटने वाला, क्रमशः।

DllMainसीआरटी के लिए कोड \ CRT \ src \ crtlib.c कुलपति के तहत वी.एस. के लिए स्थापित निर्देशिका में पाया जा सकता है।


महान प्रारंभिक बिंदु। थोड़ा डिबगिंग के साथ एक __CRTDLL_INIT को एक सांख्यिकीय रूप से जुड़े CRT के लिए भी कहा जाता है। कॉलस्टैक इनिट को _LdrpCallInitRoutine @ 16 () से पुकारा जाता है, मुझे यकीन नहीं है कि क्या तंत्र द्वारा किया गया है। इसका मतलब है कि हाल ही में CRT के साथ सिग्नल को संभालने के अपवाद के साथ सभी आरंभीकरण / विखंडन सही ढंग से किया जाता है, जो अभी भी _threadstartex सहायक फ़ंक्शन में किया जाता है जिसे शुरुआत से बुलाया गया है, लेकिन CreateThread से नहीं। शायद आप इसे उत्तर में जोड़ सकते हैं और मैं इनाम में पुरस्कार दूंगा?
सुमा

बाउंटी को सम्मानित किया गया, क्योंकि यह सबसे ज्यादा मददगार लगता है। फिर भी, जवाब शायद अपडेट करने लायक हो सकता है। यदि आप ऐसा नहीं कर सकते हैं, तो मैं इसे कुछ दिनों के भीतर दोबारा देख सकता हूं।
सुमा

1
@MSN: कृपया ध्यान रखें कि CreateThread अभी भी एक DLL में खराब है, यदि आप फिर से स्थैतिक CRT को लिंक कर रहे हैं और DisableThreadLibraryCalls को कॉल किया है, जो DLL_THREADDDETACH के लिए कॉल को निष्क्रिय करता है। तब आपको मेमोरी लीक्स मिलेंगे। यह मेरे KB आलेख में यहाँ प्रलेखित है: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach

17

यह _beginthreadex(देखें crt\src\threadex.c) के मूल में कोड है :

    /*
     * Create the new thread using the parameters supplied by the caller.
     */
    if ( (thdl = (uintptr_t)
          CreateThread( (LPSECURITY_ATTRIBUTES)security,
                        stacksize,
                        _threadstartex,
                        (LPVOID)ptd,
                        createflag,
                        (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
    {
            err = GetLastError();
            goto error_return;
    }

बाकी _beginthreadexCRT के लिए प्रति-थ्रेड डेटा संरचना प्रारंभ करता है।

उपयोग करने _beginthread*का लाभ यह है कि धागे से आपकी सीआरटी कॉल सही ढंग से काम करेगी।


12

आपको उपयोग करना चाहिए _beginthreadया_beginthreadex सी रनटाइम लाइब्रेरी का करने की अनुमति इसे स्वयं थ्रेड का प्रारंभ करना चाहिए। केवल C / C ++ प्रोग्रामर को यह जानने की आवश्यकता है क्योंकि उन्हें अब अपने स्वयं के विकास पर्यावरण का उपयोग करने के नियम चाहिए।

यदि आप उपयोग करते _beginthreadहैं तो आपको कॉल करने की आवश्यकता नहीं है CloseHandleक्योंकि RTL आपके लिए करेगा। यही कारण है कि यदि आपने उपयोग किया है तो आप हैंडल पर प्रतीक्षा नहीं कर सकते _beginthread। भी_beginthread भ्रम होता है, तो धागा समारोह बाहर निकलता है तुरंत (जल्दी) शुरू धागे के रूप में धागा यह सिर्फ शुरू की करने के लिए गलत धागा संभाल पकड़े नहीं छोड़ा जा सकता है मेरी।

_beginthreadex हैंडल का उपयोग प्रतीक्षा के लिए किया जा सकता है लेकिन इसके लिए एक स्पष्ट कॉल की भी आवश्यकता होती है CloseHandle । यह वही है जो प्रतीक्षा के साथ उपयोग करने के लिए उन्हें सुरक्षित बनाता है। इसे पूरी तरह से मूर्ख बनाने के लिए अन्य मुद्दा हमेशा निलंबित धागे को शुरू करना है। सफलता, रिकॉर्ड संभाल आदि के लिए जाँच करें। फिर से शुरू करें धागा। लॉन्च थ्रेड को उसके हैंडल को रिकॉर्ड करने से पहले एक धागे को समाप्त होने से रोकने के लिए यह आवश्यक है।

सर्वश्रेष्ठ अभ्यास का उपयोग करना है _beginthreadex, निलंबित करना शुरू करें फिर रिकॉर्डिंग संभाल के बाद फिर से शुरू करें , हैंडल पर प्रतीक्षा करें ठीक है, CloseHandleकॉल किया जाना चाहिए।


8

CreateThread()जब आप अपने कोड में किसी भी CRT फ़ंक्शंस का उपयोग करते हैं, तो मेमोरी लीक होते थे। _beginthreadex()के रूप में एक ही पैरामीटर है CreateThread()और यह की तुलना में अधिक बहुमुखी है _beginthread()। इसलिए मैं आपको उपयोग करने की सलाह देता हूं _beginthreadex()


2
1999 का लेख, जब से तय किया गया है
bobobobo

1
2005 का यह लेख अभी भी पुष्टि करता है कि कोई समस्या है।
Jaywalker

2
हाँ, यह केवल MSVC ++ 6.0 सर्विस पैक 5 और इससे पहले लागू होता है। ("विस्तार योग्य ड्रॉपडाउन पर लागू होता है" देखें)। यदि आप VC7 या उससे ऊपर का उपयोग कर रहे हैं तो यह आज का मुद्दा नहीं है।
बोब्बोबो

1
यह अभी भी एक मुद्दा है, अगर आप फिर से स्थैतिक CRT लिंक करते हैं! इसके अलावा यह अभी भी एक समस्या है अगर आप एक DLL में DisableThreadLibraryCalls को कॉल करते हैं जो कि सांख्यिकीय रूप से जुड़ा हुआ है; मेरा KB लेख देखें: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach

2
आपने जानकारी को गलत तरीके से प्रस्तुत किया है: कभी भी मेमोरी को लीक नहींCreateThread करता है । यह बल्कि CRT है जो करता है, जब एक थ्रेड से बुलाया जाता है जिसे ठीक से प्रारंभ नहीं किया गया है।
IInspectable

6

अपने अपडेट किए गए सवाल के बारे में: "मैं भी स्थानों है कि मैं फोन नहीं कर सकते हैं की एक जोड़ी में पढ़ा है WaitForSingleObject()कि अगर मैं इस्तेमाल किया _beginthread(), लेकिन अगर मैं फोन _endthread()सूत्र में नहीं करना चाहिए कि काम करता है?"

सामान्य तौर पर, आप थ्रेड हैंडल पास कर सकते हैं WaitForSingleObject()(या अन्य एपीआई जो ऑब्जेक्ट हैंडल पर प्रतीक्षा करते हैं) को ब्लॉक करने के लिए जब तक कि थ्रेड पूरा नहीं हो जाता। लेकिन इसके द्वारा बनाया गया थ्रेड हैंडल _beginthread()बंद हो _endthread()जाता है जब कहा जाता है (जो स्पष्ट रूप से किया जा सकता है या थ्रेड प्रक्रिया के वापस आने के समय अंतर्निहित रूप से किया जाता है)।

समस्या को प्रलेखन के लिए बाहर बुलाया गया है WaitForSingleObject():

यदि यह हैंडल बंद है जबकि प्रतीक्षा अभी भी लंबित है, तो फ़ंक्शन का व्यवहार अपरिभाषित है।


5

फ़ंक्शन हस्ताक्षरों को देखते हुए, CreateThreadलगभग समान है _beginthreadex

_beginthread,_beginthreadx बनामCreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

यहाँ कहा गया है कि टिप्पणी या _beginthreadतो प्रारंभ बिंदु के रूप में __cdeclया __clrcallसम्मेलन का _beginthreadexउपयोग कर सकती है , और प्रारंभ बिंदु के लिए __stdcallया तो उपयोग कर सकती है __clrcall

मुझे लगता है कि स्मृति लीक पर लोगों द्वारा की गई कोई भी टिप्पणी CreateThreadएक दशक से अधिक पुरानी है और शायद इसे अनदेखा किया जाना चाहिए।

दिलचस्प है, दोनों _beginthread*फ़ंक्शन वास्तव CreateThreadमें हुड के तहत कॉल करते हैं, C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\srcमेरी मशीन पर।

// From ~line 180 of beginthreadex.c
/*
 * Create the new thread using the parameters supplied by the caller.
 */
if ( (thdl = (uintptr_t)
      CreateThread( (LPSECURITY_ATTRIBUTES)security,
                    stacksize,
                    _threadstartex,
                    (LPVOID)ptd,
                    createflag,
                    (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
{
        err = GetLastError();
        goto error_return;
}


3

beginthreadexआप HANDLEमें WaitForSingleObjectऔर दोस्तों में उपयोग के लिए एक धागा देता है । beginthreadऐसा नहीं करता। CloseHandle()जब आप कर रहे हैं मत भूलना । असली उत्तर boost::threadC ++ 09 के थ्रेड क्लास का उपयोग या जल्द ही करना होगा ।


एमएसडीएन विवरण कहता है कि "सफल होने पर, इनमें से प्रत्येक फ़ंक्शन नए बनाए गए थ्रेड को संभालता है;" _beginthread () और _beginthreadex () ...
Kiril

@Kiril: लेकिन फिर प्रलेखन यह कहकर चला जाता है कि _beginthread आपके लिए हैंडल बंद कर देता है, जिसका अर्थ है कि आप इसका उपयोग नहीं कर सकते हैं यदि थ्रेड जल्दी से बाहर निकलता है ...
रोजर लिप्सकॉम्ब

2

की तुलना में _beginthread, _beginthreadexआप कर सकते हैं:

  1. सुरक्षा विशेषताओं को निर्दिष्ट करें।
  2. निलंबित स्थिति में एक धागा शुरू करें।
  3. आप थ्रेड आईडी प्राप्त कर सकते हैं जिसका उपयोग किया जा सकता है OpenThread
  4. यदि कॉल सफल रहा तो थ्रेड हैंडल लौटाया जाना मान्य है। वहाँ आप के साथ संभाल को बंद करने की जरूरत है CloseHandle
  5. लौटाया गया थ्रेड हैंडल का उपयोग सिंक्रनाइज़ेशन API के साथ किया जा सकता है।

_beginthreadexमिलता-जुलता CreateThreadहै, लेकिन पूर्व एक CRT कार्यान्वयन और बाद एक Windows API कॉल है। CreateThread के दस्तावेज़ में निम्नलिखित अनुशंसाएँ शामिल हैं:

एक निष्पादन योग्य में एक धागा जो C रन-टाइम लाइब्रेरी (CRT) को कॉल करता है , उसे थ्रेड प्रबंधन के लिए _beginthreadexऔर _endthreadexकार्यों का उपयोग करना चाहिए बजाय CreateThreadऔर ExitThread; इसके लिए CRT के बहु-थ्रेडेड संस्करण के उपयोग की आवश्यकता है। यदि एक थ्रेड CreateThreadसीआरटी का उपयोग करके बनाया गया है, तो सीआरटी कम-स्मृति स्थितियों में प्रक्रिया को समाप्त कर सकता है।


एपीआई विनिर्देश के अनुसार, बुलेट अंक 3-5 के लिए अद्वितीय नहीं हैं _beginthreadex। आप uintptr_tदोनों कार्यों से रिटर्न कास्ट कर सकते हैं HANDLE
एंडॉन एम। कोलमैन

हां, आप सिद्धांत में सही हैं। व्यवहार में, अंतर यह है कि _beginthreadबाहर निकलने पर संभाल बंद कर देता है। तो आप मज़बूती से हैंडल का उपयोग सिंक्रोनाइज़ेशन API के साथ या थ्रेड आईडी प्राप्त करने के लिए नहीं कर सकते हैं और जब तक आप हैंडल को सिंक्रनाइज़ और डुप्लिकेट करने के लिए किसी अन्य तरीके का उपयोग नहीं करते हैं। लेकिन फिर _beginthreadexयह आपके लिए कर रहा है।
विशाल

2

CreateThread()एक बार कोई नहीं था, क्योंकि CRT गलत तरीके से शुरू / साफ हो जाएगा। लेकिन यह अब इतिहास है: CreateThread()सीआरटी को तोड़ने के बिना अब एक (वीएस2010 और शायद कुछ संस्करणों का उपयोग करके) कॉल किया जा सकता है।

यहाँ आधिकारिक एमएस पुष्टि है । यह एक अपवाद बताता है:

असल में, केवल एक फ़ंक्शन जिसे उपयोग किए गए थ्रेड में नहीं किया जाना चाहिए CreateThread()वह signal()फ़ंक्शन है।

हालांकि, निरंतरता के दृष्टिकोण से, मैं व्यक्तिगत रूप से उपयोग करते रहना पसंद करता हूं _beginthreadex()


जबकि मुझे लगता है कि यह सच है, क्या आप कुछ आधिकारिक प्रमाण प्रदान कर सकते हैं - या तो एमएस डॉक्यूमेंटेशन से लिंक करके, या सीआरटी _beginthreadex / _endthreadex स्रोतों का विश्लेषण करके?
सुमा

@ सुमा, मुझे लगता है कि आपने अपनी टिप्पणी टाइप करते समय मैंने एमएस लिंक जोड़ा ;-)
सर्जियन वुटिएर

जिस दस्तावेज़ को आप लिंक कर रहे हैं, वह पुष्टि नहीं करता है: "हालांकि, सीआरटी कार्यों को क्या कहा जाता है, इसके आधार पर, थ्रेड समाप्त होने पर एक छोटी मेमोरी लीक हो सकती है।" इसका मतलब है कि यह अब एक बड़ा और सामान्य नहीं-नहीं है, लेकिन फिर भी एक नहीं-नहीं है यदि आप अक्सर थ्रेड बना रहे हैं और उन कार्यों का उपयोग कर रहे हैं। हालाँकि, दस्तावेज़ 2005 से है और इसलिए इस मामले की हाल की स्थिति को संबोधित नहीं कर सकता।
सुमा

1
हम्म ... हालाँकि यह उपयोग के मामले पर निर्भर हो सकता है, एक मेमोरी रिसाव को छोड़ने वाला एक फ़ंक्शन, चाहे कोई भी आकार हो, मैं एक नो-नो पर विचार करूंगा ... - विशेष रूप से अगर कोई गैर-लीकिंग विकल्प है!
alk

"एक अब CRT को तोड़े बिना CreateThread () कह सकते हैं।" - दुर्भाग्य से, यह सच नहीं है, और कभी नहीं रहा है। से CreateThread : "एक निष्पादन योग्य है कि सी चलाने के समय पुस्तकालय (सीआरटी) कॉल में एक धागा धागा प्रबंधन के लिए _beginthreadex और _endthreadex कार्यों का उपयोग करना चाहिए [...] एक धागा CreateThread सीआरटी कॉल उपयोग कर बनाई गई हैं, सीआरटी समाप्त कर सकता है कम-स्मृति स्थितियों में प्रक्रिया। "
IInspectable

2

CreateThread()विंडोज एपीआई कॉल है जो भाषा तटस्थ है। यह सिर्फ OS ऑब्जेक्ट बनाता है - थ्रेड और इस थ्रेड को HANDLE लौटाता है। सभी विंडोज़ अनुप्रयोग थ्रेड बनाने के लिए इस कॉल का उपयोग कर रहे हैं। सभी भाषाओं में स्पष्ट कारणों के लिए प्रत्यक्ष एपीआई कॉल से बचा जाता है: 1. आप नहीं चाहते कि आपका कोड ओएस विशिष्ट हो 2. आपको एपीआई कॉल करने से पहले कुछ घर रखने की आवश्यकता है: मापदंडों और परिणामों को परिवर्तित करें, अस्थायी भंडारण आदि का आवंटन करें।

_beginthreadex()CreateThread()C विशिष्ट के लिए उस खाते के चारों ओर C आवरण है । यह थ्रेड विशिष्ट भंडारण को आवंटित करके मल्टीथ्रेडेड वातावरण में मूल सिंगल थ्रेडेड सी एफ-एनएस काम करता है।

यदि आप CRT का उपयोग नहीं करते हैं तो आप सीधे कॉल से बच नहीं सकते CreateThread()। यदि आप CRT का उपयोग करते हैं, तो आपको अवश्य उपयोग करना चाहिए _beginthreadex()या कुछ CRT स्ट्रिंग f-ns पूर्व VC2005 से ठीक से काम नहीं कर सकते हैं।


1

CreateThread()स्ट्रेट सिस्टम कॉल है। यह लागू किया गया है Kernel32.dll, जिस पर , संभवतः, आपका आवेदन पहले से ही अन्य कारणों से जुड़ा हुआ है। यह हमेशा आधुनिक विंडोज सिस्टम में उपलब्ध है।

_beginthread()और _beginthreadex()Microsoft C रनटाइम ( msvcrt.dll) में आवरण कार्य हैं । दस्तावेज़ में दो कॉल के बीच अंतर बताया गया है। यह तब उपलब्ध होता है जब Microsoft C रनटाइम उपलब्ध होता है, या यदि आपका एप्लिकेशन इसके विरुद्ध वैधानिक रूप से जुड़ा हुआ है। जब तक आप शुद्ध विंडोज एपीआई में कोडिंग नहीं करेंगे, तब तक आप संभवतः उस लाइब्रेरी से भी जुड़ेंगे।

आपका प्रश्न एक सुसंगत और वास्तव में एक आवर्ती है। कई एपीआई के रूप में, विंडोज एपीआई में हमें डुप्लिकेट और अस्पष्ट कार्यक्षमता से निपटना पड़ता है। सबसे बुरी बात, दस्तावेज़ीकरण इस मुद्दे को स्पष्ट नहीं करता है। मुझे लगता है कि _beginthread()कार्यों के परिवार को अन्य मानक सी कार्यात्मकताओं के साथ बेहतर एकीकरण के लिए बनाया गया था, जैसे कि हेरफेर errno_beginthread()इस प्रकार सी रनटाइम के साथ बेहतर एकीकृत करता है।

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

उपयोग करने का एक अच्छा कारण _beginthread() होगा (जैसा कि यह झूठा प्रतीत होता है) कि सी ++ वस्तुओं को ठीक से खोल दिया जाएगा / नष्ट कर दिया जाएगा यदि _endthread()कहा जाता है।


कोई अस्पष्ट फ़ंक्शन कॉल बिल्कुल नहीं हैंCreateThreadएक धागा बनाने के लिए विंडोज एपीआई कॉल है। यदि आप CRT का उपयोग कर रहे हैं (क्योंकि आप C या C ++ में प्रोग्रामिंग कर रहे हैं), तो आपको CRT के _beginthread[ex]कॉल (जो CreateThreadआवश्यक CRT इनिशियलाइज़ेशन करने के अतिरिक्त कॉल करते हैं) का उपयोग करके थ्रेड्स बनाने चाहिए । _beginthreadऔर पूर्व-संस्करण के बीच सबसे महत्वपूर्ण अंतर : पूर्व में देशी थ्रेड हैंडल का स्वामित्व बरकरार रहता है, जबकि बाद वाला कॉल करने वाले के पास स्वामित्व रखता है।
IInspectable

Nitpick: msvcrt.dllहै नहीं सी क्रम DLL! देखें blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273
गोविंद परमार

0

Win32 API फ़ंक्शन को लपेटने वाले C रन-टाइम फ़ंक्शन को कॉल करने के निहितार्थ पर चर्चा करने के लिए अन्य उत्तर विफल हो जाते हैं। DLL लोडर लॉकिंग व्यवहार पर विचार करते समय यह महत्वपूर्ण है।

_beginthread{ex}अन्य उत्तरों पर चर्चा के रूप में कोई विशेष सी रनटाइम थ्रेड / फाइबर मेमोरी प्रबंधन करता है या नहीं , इसे (डी रन-टाइम के लिए सी लिंकिंग को गतिशील मानते हुए) कार्यान्वित किया जाता है कि प्रक्रियाएं अभी तक लोड नहीं हुई हैं।

इससे कॉल करना सुरक्षित नहीं _beginthread*है DllMain। मैंने विंडोज "AppInit_DLLs" सुविधा का उपयोग करके लोड किए गए DLL को लिखकर इसका परीक्षण किया है। बूटअप के दौरान कामकाज बंद करने के लिए विंडोज के महत्वपूर्ण हिस्सों में से एक बहुत _beginthreadex (...)से CreateThread (...)कारणों के बजाय कॉल करना DllMainक्योंकि लोडर लॉक का इंतजार करने के लिए कुछ आरंभीकरण कार्यों को करने के लिए जारी किया जाना चाहिए।

संयोग से, यही कारण है कि कर्नेल 32.dll में बहुत सारे अतिव्यापी स्ट्रिंग फ़ंक्शन हैं जो C रन-टाइम भी करता है - DllMainउसी तरह की स्थिति से बचने के लिए उन का उपयोग करें ।


0

यदि आप जेफरी रिक्टर से डिबगिंग विंडोज एप्लिकेशन पुस्तक पढ़ते हैं, तो वह बताते हैं कि लगभग सभी उदाहरणों में आपको कॉल _beginthreadexकरने के बजाय कॉल करना होगा CreateThread_beginthreadचारों ओर एक सरलीकृत आवरण है _beginthreadex

_beginthreadexकुछ CRT (C RunTime) इंटर्न को शुरू करता है जो CreateThreadAPI नहीं करेगा।

एक परिणाम अगर आप CRT फ़ंक्शन को कॉल CreateThreadका उपयोग करने के बजाय API का उपयोग करते _begingthreadexहैं तो अप्रत्याशित कारण समस्या हो सकती है।

इस पुराने Microsoft जर्नल को रिक्टर से देखें।


-2

दोनों में अब कोई अंतर नहीं है।

मेमोरी लीक आदि के बारे में सभी टिप्पणियां बहुत पुराने <VS2005 संस्करणों पर आधारित हैं। मैंने सालों पहले कुछ तनाव परीक्षण किए हैं और इस मिथक को खत्म कर सकता हूं। यहां तक ​​कि Microsoft अपने उदाहरणों में शैलियों को मिलाता है, लगभग कभी भी _beginthread का उपयोग नहीं करता है।


CreateThread : "अगर CreateThread का उपयोग करके बनाया गया एक धागा CRT कहता है, तो CRT कम-मेमोरी स्थितियों में प्रक्रिया को समाप्त कर सकता है।"
IInspectable

आधार के आधार पर "CRT के मल्टीथ्रेड संस्करण के उपयोग की आवश्यकता है" मुझे लगता है कि यह दस्तावेज़ीकरण कचरा है क्योंकि अब और कई वर्षों से कोई मल्टीथ्रेडेड crt संस्करण नहीं है।
लोथर

"अब कोई मल्टीथ्रेडेड crt संस्करण नहीं है" - MSDN का दावा है कि "[t] वह एकल-थ्रेडेड CRT अब उपलब्ध नहीं है।" तुम दोनों सही नहीं हो सकते। मैं यहाँ MSDN के साथ भी जाऊँगा।
IInspectable

यह एक टाइपो था, निश्चित रूप से मेरा मतलब था कि एकल थ्रेडेड चला गया है और मल्टीथ्रेडेड मानक बन गया है और जो चला गया है वह थ्रेड्स का उपयोग करने या न करने के बीच अंतर है।
लोथर

यह वास्तव में अजीब हो रहा है। अब आप एक बयान का उपयोग कर रहे हैं, यह निस्संदेह सही है ( "सीआरटी के मल्टीथ्रेडेड संस्करण के उपयोग की आवश्यकता है" ) यह दावा करने के लिए कि यह कथन और साथ ही साथ शेष दस्तावेज बहुत गलत है? यकीन है कि सही नहीं लगता है।
IInspectable
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.