উইন্ডোজ থ্রেডিং: _বেগিনথ্রেড বনাম _বেগিনথ্রেডেক্স বনাম ক্রিয়েটথ্রেড সি ++


133

থ্রেড শুরু করার আরও ভাল উপায় কী _beginthread, _beginthreadxবা CreateThread?

আমি কোনটি সুবিধার / অসুবিধেও আছে চেষ্টা করছি _beginthread, _beginthreadexএবং CreateThread। এই সমস্ত ফাংশন একটি নতুন নির্মিত থ্রেডে একটি থ্রেড হ্যান্ডেল ফিরিয়ে দেয়, আমি ইতিমধ্যে জানি যে ক্রিয়েটথ্রেড যখন একটি ত্রুটি দেখা দেয় তখন কিছুটা অতিরিক্ত তথ্য সরবরাহ করে (এটি কল করে চেক করা যায় GetLastError) ... তবে আমার যখন কিছু বিবেচনা করা উচিত তখন কী করা উচিত ' আমি এই ফাংশন ব্যবহার করছি?

আমি একটি উইন্ডোজ অ্যাপ্লিকেশন নিয়ে কাজ করছি, সুতরাং ক্রস-প্ল্যাটফর্মের সামঞ্জস্যতা ইতিমধ্যে প্রশ্নটির বাইরে।

আমি এমএসডিএন ডকুমেন্টেশনটি পেরিয়েছি এবং আমি ঠিক বুঝতে পারি না, উদাহরণস্বরূপ, কেউ কেন ক্রিয়েটথ্রেডের পরিবর্তে বা বিগেনথ্রেড ব্যবহার করার সিদ্ধান্ত নেবে।

চিয়ার্স!

আপডেট: ঠিক আছে, সমস্ত তথ্যের জন্য ধন্যবাদ, আমি কয়েকটি জায়গায় পড়েছি যেগুলি WaitForSingleObject()আমি ব্যবহার করলে কল করতে পারি না _beginthread(), তবে আমি যদি _endthread()থ্রেডে কল করি তবে সে কাজ করা উচিত নয়? সেখানে চুক্তি কি?


2
সি / সি ++ প্রোগ্রামারদের জন্য _beginthreadex () কী করে সে সম্পর্কে একটি বিশ্লেষণ যা আমি এলি বেন্ডারস্কির ওয়েবসাইটে লিঙ্ক থেকে পেয়েছি। এটি ক্রিয়েটথ্রেড () ব্যবহার করবেন কিনা তা প্রশ্নোত্তর থেকে নেওয়া। মাইক্রোসফটস
রিচার্ড চেম্বারস

উত্তর:


96

CreateThread() কার্নেল স্তরে নিয়ন্ত্রণের অন্য থ্রেড তৈরির জন্য একটি কাঁচা উইন 32 এপিআই কল।

_beginthread()& _beginthreadex()সি রানটাইম লাইব্রেরি কলগুলি CreateThread()পর্দার পিছনে কল । একবার CreateThread()ফিরে আসার পরে, _beginthread/ex()নতুন থ্রেডে সি রানটাইম লাইব্রেরিটি ব্যবহারযোগ্য ও ধারাবাহিক করতে অতিরিক্ত বুককিপিংয়ের যত্ন নেয়।

সি ++ এ আপনার অবশ্যই প্রায়শই ব্যবহার করা উচিত _beginthreadex()যদি না আপনি সি রানটাইম লাইব্রেরিতে মোটামুটি লিঙ্ক না করেন (ওরফে এমএসভিসিআরটি * .ডিল / .লিব)।


39
এটি এখন আগের মতো ঠিক তেমন সত্য নয়। সিআরটি তার সংকেত () ফাংশন ব্যতীত ক্রিয়েটিথ্রেড () দ্বারা নির্মিত একটি থ্রেডে সঠিকভাবে কাজ করবে। সিআরটি ব্যবহার করে ক্রিয়েটথ্রেড () দিয়ে তৈরি প্রতিটি থ্রেডের জন্য একটি ছোট মেমরি ফাঁস (~ 80 বাইট) থাকবে তবে এটি সঠিকভাবে কাজ করবে। আরও তথ্যের জন্য দেখুন: সমর্থন.
microsoft.com/default.aspx/kb/104641

1
@ জন: আসলে এই বাগটি কেবলমাত্র এমএসভিসি ++ 6.0
বোবোবো

5
@ বোবোবো: ভাল প্রশ্ন। আমি কেবল অনুমান করতে পারি যে এমএস মূলত _beginরুটিনগুলিকে অভ্যন্তরীণ কল হিসাবে চিহ্নিত করা CreateThreadহয়েছিল এবং সবাইকে কল করবে এমন API ফাংশন হওয়ার কথা। আর একটি সম্ভাব্য ব্যাখ্যা হ'ল এমএসের স্ট্যান্ডার্ডকে অগ্রাহ্য করার এবং জিনিসগুলির নামকরণ সম্পর্কে খুব খারাপ সিদ্ধান্ত নেওয়ার একটি দীর্ঘ ও গৌরবময় ইতিহাস রয়েছে।
জন ডিবলিং

15
_beginফাংশন একটি আন্ডারস্কোর দিয়ে শুরু কারণ মাইক্রোসফট আরো ঘনিষ্ঠভাবে মান অনুসরণ করতে শুরু করে। সি রানটাইমে, আন্ডারস্কোর সহ থাকা নামগুলি প্রয়োগের জন্য সংরক্ষিত রয়েছে (এবং প্রয়োগগুলি এগুলি হিসাবে তাদের শেষ-ব্যবহারকারীর ব্যবহারের জন্য ডকুমেন্ট করতে পারে)। beginthreadex()এমন একটি নাম যা ব্যবহারকারীর ব্যবহারের অনুমতিপ্রাপ্ত। যদি সি রানটাইম এটি ব্যবহার করে, তবে এটি ব্যবহারকারীর কাছে প্রত্যাশা করতে সক্ষম হওয়ার বৈধ অধিকার ছিল এমন একটি শেষ ব্যবহারকারীর প্রতীকটির সাথে দ্বন্দ্ব হতে পারে। মনে রাখবেন যে উইন 32 এপিআইগুলি সি রানটাইমের অংশ নয় এবং তারা ব্যবহারকারীর নেমস্পেস ব্যবহার করে।
মাইকেল বুড়

2
@Lothar আছে: হয় Win32 API কল মধ্যে পার্থক্য CreateThreadএবং সিআরটি কল _beginthread/ex, এবং যখন একটি থ্রেডে সিআরটি কলিং, এটা সবসময় সঙ্গে তৈরি করা উচিত _beginthread/ex। আপনি যদি না করেন তবে আর মেমরি ফাঁস হতে পারে না। CreateThreadউদাহরণস্বরূপ, কল করার সময় আপনি অবশ্যই আপনার ভাসমান পয়েন্ট পরিবেশ সঠিকভাবে শুরু করতে পারবেন না । আছে আরো : "একটি থ্রেড ব্যবহার করে তৈরি করা তাহলে CreateThread সিআরটি কল সিআরটি কম মেমরি অবস্থার প্রক্রিয়া বিনষ্ট করতে পারেন।"
IInspectable

37

এর মধ্যে বেশ কয়েকটি পার্থক্য রয়েছে _beginthread() এবং _beginthreadex()_beginthreadex()আরও বেশি পছন্দ করার জন্য তৈরি করা হয়েছিল CreateThread()(উভয় প্যারামিটারে এবং এটি কীভাবে আচরণ করে)।

ড্র্রু হল হিসাবে উল্লেখ করেছে, আপনি যদি সি / সি ++ রানটাইম ব্যবহার করেন তবে আপনার অবশ্যই তার পরিবর্তে _beginthread()/ ব্যবহার করতে হবে যাতে রানটাইমটির নিজস্ব থ্রেড আরম্ভকরণ (থ্রেড স্থানীয় স্টোরেজ সেটআপ করা ইত্যাদি) সম্পাদনের সুযোগ থাকে।_beginthreadex()CreateThread()

অনুশীলনে, এর অর্থ এটি CreateThread()আপনার কোড দ্বারা সরাসরি কখনও ব্যবহার করা উচিত নয়।

এর জন্য এমএসডিএন ডকুমেন্টস _beginthread()_beginthreadex()পার্থক্যগুলির / এর কিছুটা বিশদ বিশদ রাখে - এর মধ্যে আরও একটি গুরুত্বপূর্ণ এটি হ'ল যেহেতু তৈরি থ্রেডের জন্য থ্রেড হ্যান্ডেলটি _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).

হালনাগাদজানুয়ারী ২০১৩ :

ভিএস ২০১২-এর সিআরটি-তে অতিরিক্ত বিট শুরু করা হয়েছে _beginthreadex(): প্রক্রিয়াটি যদি "প্যাকেজড অ্যাপ্লিকেশন" হয় (যদি কিছু কার্যকর থেকে ফিরে আসে GetCurrentPackageId()) রানটাইম সদ্য নির্মিত থ্রেডে এমটিএ আরম্ভ করবে।


3
সেখানে হয় উপযুক্ত বার যখন CreateThread () warranted হয়, কিন্তু সত্যি বলতে আপনি কি সত্যিই এটা করতে আপনার পথ থেকে সরে যেতে হবে। আমরা পোর্টেবল কোনও কিছুর সম্পূর্ণ অভাবের কথা বলছি এবং একচেটিয়া WIN32 এপিআই ডিএলএল বা অ্যাপ লিখছি। কোনও সি-রানটাইম কল সহ নয়। এমনকি এসটিএল ব্যবহার সীমাবদ্ধ যা আপনাকে WIN32 মেমরি পরিচালন ফাংশনগুলি ব্যবহার করতে কাস্টম বরাদ্দ সরবরাহ করতে হবে। বিকাশকারী স্টুডিওর সাথে এটি করার সেটআপ নিজেই একটি কাজ, তবে সবচেয়ে ছোট পায়ের ছাপ সহ একমাত্র চিরতরে WIN32 লিবিয়ের জন্য এটি করা যেতে পারে। তবে হ্যাঁ, এটি প্রায় সকলের পক্ষে রক্তক্ষয়ী নয় তবে খুব কয়েকটি নির্বাচিত রয়েছে।
WhozCraig

1
@ ভোজক্রাইগ: সিআরটি বাদ দিলে আরও মারাত্মক সীমাবদ্ধতা রয়েছে। সর্বাধিক বিশিষ্ট ব্যক্তিরা হলেন: কোনও 64-বিট পূর্ণসংখ্যার সমর্থন, কোনও ভাসমান বিন্দু সমর্থন নয় এবং - অত্যন্ত মারাত্মকভাবে - কোনও ব্যতিক্রম হ্যান্ডলিং নেই। এর অর্থ হ'ল কোনও ব্যতিক্রম হ্যান্ডলিং - মোটেই নয় । এমনকি এসইএইচ ব্যতিক্রম নয়। এটি তৈরি করা বিশেষত শক্ত এবং CreateThreadডান থিং হওয়ার জন্য সম্ভাবনা হ্রাস পেতে পাতলা।
IInspectable

@ মিশেলবার: আপনি ভিসি ++ 2015 এর জন্য আপনার উত্তরটি আপডেট করতে চাইতে পারেন ।
ব্যবহারকারী541686

@ মেহরদাদ: কোন পরিবর্তনগুলি বিশেষভাবে উল্লেখ করার মতো বলে মনে করেন?
IInspectable

আমি খুঁজে পেয়েছি যে ডিসিয়েবলথ্রেডলিবারি কলগুলি ক্রিয়েটথ্রেড দিয়ে তৈরি থ্রেডগুলিতে কোনও প্রভাব ফেলবে না, তবে _বেগিনথ্রেড বা _বেগিনথ্রেডেক্স দ্বারা তৈরি থ্রেড অক্ষম করে।
11

23

সাধারণভাবে, করণীয় সঠিক জিনিস হ'ল কল _beginthread()/_endthread()(বা ex()রূপগুলি)। তবে, আপনি যদি সিআরটিকে .dll হিসাবে ব্যবহার করেন, সিআরটি রাষ্ট্র যথাযথভাবে শুরু হবে এবং ধ্বংস হবে কারণ সিআরটি'র DllMainসাথে ডাকা হবে DLL_THREAD_ATTACHএবং DLL_THREAD_DETACHফোন করা CreateThread()এবং ExitThread()ফিরে আসার সময় যথাক্রমে হবে।

DllMainসিআরটি কোড \ সিআরটি \ src \ crtlib.c ভিসি অধীনে বনাম জন্য ইনস্টল ডিরেক্টরির মধ্যে পাওয়া যেতে পারে।


দুর্দান্ত সূচনা পয়েন্ট। সামান্য ডিবাগিংয়ের মাধ্যমে একজন দেখতে পাবে __CRTDLL_INIT কে এমনকি স্ট্যাটিকালি সংযুক্ত CRT- এর জন্য ডাকা হয়। কলস্ট্যাক থ্রিকে _LdrpCallInitRoutine @ 16 () থেকে কল করা হয়েছে, আমি ঠিক কোন প্রক্রিয়াতে নিশ্চিত নই। এর অর্থ সাম্প্রতিক সিআরটি-র সাহায্যে সমস্ত সূচনা / ডিনিটালাইজেশন সঠিকভাবে সিগন্যাল হ্যান্ডলিং ব্যতীত সম্পন্ন করা হয়, যা এখনও আরম্ভথ্রেড থেকে ডাকা _threadstartex সহায়ক ফাংশনে করা হয়, তবে ক্রিয়েটথ্রেড থেকে নয়। সম্ভবত আপনি উত্তরে এটি যুক্ত করতে পারেন এবং আমি অনুগ্রহটি দেব?
সুমা

অনুদান পুরষ্কার দেওয়া হয়েছে, কারণ এটি সবচেয়ে সহায়ক বলে মনে হচ্ছে। তবুও, উত্তর সম্ভবত আপডেট করার উপযুক্ত হতে পারে। আপনি যদি এটি না করতে পারেন তবে আমি কয়েক দিনের মধ্যে এটি আবার দেখতে পাব।
সুমা

1
@ এমএসএন: দয়া করে সচেতন হন, ক্রিয়েটিথ্রেড এখনও কোনও ডিএলএল-তে খারাপ আছে, আপনি যদি আবার স্থির সিআরটি-র সংযোগ করছেন এবং ডিজেবল_ড্রেডলিবারি কলগুলি কল করে যা ডিএলএল_থ্রেড_ডাটাচ এর জন্য কলগুলি অক্ষম করে। তারপরে আপনি মেমরি ফাঁস পাবেন। এটি আমার কেবি নিবন্ধে এখানে নথিভুক্ত করা হয়েছে: সমর্থন.
microsoft.com/kb/555563/en-us

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;
    }

বাকি _beginthreadexসিআরটি জন্য প্রতি থ্রেড ডাটা স্ট্রাকচার সূচনা।

ব্যবহারের সুবিধা _beginthread*হ'ল থ্রেড থেকে আপনার সিআরটি কলগুলি সঠিকভাবে কাজ করবে।


12

আপনার ব্যবহার করা উচিত _beginthreadবা_beginthreadexআপনার থ্রেডটির নিজস্ব সূচনাটি সি রানটাইম লাইব্রেরিটি করার করার অনুমতি দেওয়া । কেবলমাত্র সি / সি ++ প্রোগ্রামারদের এটি জানা উচিত কারণ তাদের এখন তাদের নিজস্ব বিকাশ পরিবেশ ব্যবহারের নিয়ম করা উচিত।

আপনি যদি ব্যবহার করেন তবে _beginthreadআপনাকে কল করার দরকার নেই CloseHandleকারণ আরটিএল আপনার জন্য করবে। এজন্য আপনি যদি হ্যান্ডেলটি ব্যবহার করেন তবে অপেক্ষা করতে পারবেন না _beginthread। এছাড়াও_beginthread বিভ্রান্তির বাড়ে যদি থ্রেড ফাংশন প্রস্থানের অবিলম্বে (দ্রুত) লঞ্চ থ্রেড হিসাবে থ্রেড এটা শুধু চালু একটি অবৈধ থ্রেড হাতল ধারণ ছেড়ে দেওয়া আমার।

_beginthreadex হ্যান্ডলগুলি অপেক্ষা করার জন্য ব্যবহৃত হতে পারে তবে এর জন্য একটি স্পষ্ট কল প্রয়োজন CloseHandle । এটি তাদের জন্য অপেক্ষা সহ ব্যবহারের জন্য সুরক্ষিত করে তোলে of একে সম্পূর্ণ বোকা বানানোর জন্য অন্যান্য সমস্যা হ'ল থ্রেড স্থগিত করা সর্বদা স্থগিত করা। সাফল্য, রেকর্ড হ্যান্ডেল ইত্যাদি পরীক্ষা করুন। প্রবর্তন থ্রেডটির হ্যান্ডেলটি রেকর্ড করার আগে কোনও থ্রেডটি সমাপ্ত হতে বাধা দিতে প্রয়োজন।

সেরা অনুশীলনটি হ'ল ব্যবহার করা _beginthreadex, স্থগিত করা শুরু করা এবং হ্যান্ডেল রেকর্ডিংয়ের পরে পুনরায় শুরু করা, হ্যান্ডেলটির অপেক্ষামান ঠিক আছে, CloseHandleঅবশ্যই ফোন করা উচিত।


8

CreateThread()আপনি যখন আপনার কোডটিতে কোনও সিআরটি ফাংশন ব্যবহার করেন তখন মেমরি ফাঁস হয়_beginthreadex()একই পরামিতি রয়েছে CreateThread()এবং এটি এর চেয়ে বেশি বহুমুখী _beginthread()। সুতরাং আমি আপনাকে ব্যবহার করার পরামর্শ দিচ্ছি _beginthreadex()


2
1999 নিবন্ধ, যেহেতু স্থির করা হতে পারে
bobobobo

1
2005 এর এই নিবন্ধটি এখনও নিশ্চিত করে যে একটি সমস্যা আছে।
জয়ওয়ালকার

2
হ্যাঁ, এটি কেবল এমএসভিসি ++ 6.0 পরিষেবা প্যাক 5 এবং এর আগে প্রযোজ্য। (প্রসারণযোগ্য ড্রপডাউন "-এ প্রয়োগ হয়" দেখুন)। আপনি ভিসি 7 বা ততোধিক ব্যবহার করে থাকলে আজ এটি কোনও সমস্যা নয়।
bobobobo

1
এটি এখনও একটি সমস্যা, যদি আপনি আবার স্থিতিশীল সিআরটি লিঙ্ক করেন! এছাড়াও যদি আপনি ডিএলএল-এ অক্ষম-ট্র্যাডলিবারি কলগুলি কল করেন যা স্থিরভাবে যুক্ত; আমার কেবি নিবন্ধটি দেখুন: সমর্থন.
microsoft.com/kb/555563/en-us

2
আপনি তথ্যটি ভুলভাবে উপস্থাপন করেছেন: মেমরিটি কখনও ফাঁস CreateThreadহয় না । এটি বরং সিআরটিই করে, যখন কোনও থ্রেড থেকে কল করা হয় যা সঠিকভাবে শুরু করা হয়নি।
IInspectable

6

আপনার আপডেট হওয়া প্রশ্ন সম্পর্কে: "আমি এমন কয়েকটি স্থানেও পড়েছি যে আমি WaitForSingleObject()যদি ব্যবহার করি তবে কল করতে পারি না _beginthread(), তবে আমি যদি _endthread()থ্রেডে কল করি তবে এটি কাজ করা উচিত নয়?"

সাধারণভাবে, আপনি WaitForSingleObject()থ্রেডটি সম্পন্ন না হওয়া অবধি ব্লক করতে কোনও থ্রেড হ্যান্ডেল (বা অন্য API গুলি যা অবজেক্ট হ্যান্ডেলের অপেক্ষায় থাকে) ব্লক করতে পারেন। তবে তৈরি থ্রেড হ্যান্ডেলটি _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;
}

2
মন্তব্য, কেন আপনার ক্রিয়েটিথ্রেড কল করা উচিত নয় এবং সেই থ্রেডে সিআরটি কলগুলিতে মিশ্রিত হওয়া উচিত (অবশ্যই এক দশক পুরানো নয়, এবং অবশ্যই তা উপেক্ষা করা উচিত নয়) : "ক্রিয়েটথ্রেড ব্যবহার করে তৈরি থ্রেড যদি সিআরটি কল করে তবে সিআরটি প্রক্রিয়াটি শেষ করতে পারে কম স্মৃতির শর্ত। "
য়

3

beginthreadexআপনাকে বন্ধুরা HANDLEব্যবহারের জন্য একটি থ্রেড দেয় WaitForSingleObjectbeginthreadনা। আপনি CloseHandle()যখন সম্পন্ন করতে ভুলবেন না । আসল উত্তরটি ব্যবহার করা boost::threadবা শীঘ্রই সি ++ 09 এর থ্রেড ক্লাস হবে class


এমএসডিএন বিবরণ বলে যে "যদি সফল হয় তবে এই প্রতিটি ফাংশন নতুন নির্মিত থ্রেডকে একটি হ্যান্ডেল ফিরিয়ে দেয়;" _বিগিনথ্রেড () এবং _ বিগেনথ্রেডেক্স () উল্লেখ করে ...
কিরিল

@ কিরিল: তবে ডকুমেন্টেশনটি আরও বলেছে যে _বেগিনথ্রেড আপনার জন্য হ্যান্ডেলটি বন্ধ করে দেয়, যার অর্থ থ্রেডটি দ্রুত বের হয়ে যায় আপনি যদি এটি ব্যবহার করতে পারবেন না ...
রজার লিপসক্বে

2

তুলনায় _beginthread, আপনার সাথে _beginthreadex:

  1. সুরক্ষা বৈশিষ্ট্য নির্দিষ্ট করুন।
  2. স্থগিত অবস্থায় একটি থ্রেড শুরু করুন।
  3. আপনি যে থ্রেড আইডিটি ব্যবহার করতে পারেন তা পেতে পারেন OpenThread
  4. কলটি সফল হলে থ্রেড হ্যান্ডেলটি বৈধ হওয়ার গ্যারান্টিযুক্ত। সেখানে আপনার সাথে হ্যান্ডেলটি বন্ধ করতে হবে CloseHandle
  5. ফেরত থ্রেড হ্যান্ডেল সিঙ্ক্রোনাইজেশন এপিআই দিয়ে ব্যবহার করা যেতে পারে।

_beginthreadexঘনিষ্ঠভাবে বর্ণনার অনুরূপ CreateThread, কিন্তু সাবেক একটি সিআরটি বাস্তবায়ন ও পরেরটির একটি উইন্ডোস API কল। ক্রিয়েটথ্রেডের ডকুমেন্টেশনে নিম্নলিখিত প্রস্তাবনা রয়েছে:

একটি এক্সিকিউটেবল যে সি রান-টাইম লাইব্রেরী (সিআরটি) কল একটি থ্রেড ব্যবহার করা উচিত _beginthreadexএবং _endthreadexপরিবর্তে থ্রেড পরিচালনার জন্য ফাংশন CreateThreadএবং ExitThread; এর জন্য সিআরটি-র একাধিক-থ্রেড সংস্করণ ব্যবহার করা দরকার। যদি থ্রেডটি CreateThreadসিআরটি কল করে তৈরি করা হয়, সিআরটি কম-স্মৃতি অবস্থায় প্রক্রিয়াটি শেষ করতে পারে।


এপিআই স্পেসিফিকেশন অনুসারে, বুলেট পয়েন্ট 3-5 স্বতন্ত্র নয় _beginthreadex। আপনি uintptr_tউভয় ফাংশন থেকে রিটার্ন কাস্ট করতে পারেন HANDLE
অ্যান্ডন এম কলম্যান

হ্যাঁ, আপনি তত্ত্বের ক্ষেত্রে ঠিক বলেছেন। অনুশীলনে, পার্থক্যটি হ'ল _beginthreadপ্রস্থান করার সময় হ্যান্ডেলটি বন্ধ করে দেওয়া হয়। সুতরাং আপনি সিঙ্ক্রোনাইজেশন এপিআই এর সাহায্যে হ্যান্ডেলটি নির্ভরযোগ্যভাবে ব্যবহার করতে পারবেন না বা যতক্ষণ না আপনি হ্যান্ডেলটিকে সিঙ্ক্রোনাইজ এবং সদৃশ করার জন্য অন্য কোনও উপায় ব্যবহার করেন ততক্ষণ থ্রেড আইডি পাবেন। তবে তারপরে _beginthreadexএটি আপনার জন্য করছে।
বিশাল

2

CreateThread()একবার হ'ল নো, কারণ সিআরটি ভুলভাবে আরম্ভ / পরিষ্কার করা হবে। তবে এটি এখন ইতিহাস: CreateThread()সিআরটি না ভেঙে এখনই কেউ (ভিএস2010 এবং সম্ভবত কয়েকটি সংস্করণ ব্যবহার করে) কল করতে পারে।

এখানে সরকারী এমএস নিশ্চিতকরণ রয়েছে । এটিতে একটি ব্যতিক্রম উল্লেখ করা হয়েছে:

আসলে, একমাত্র ফাংশন যা দিয়ে তৈরি থ্রেডে ব্যবহার করা উচিত নয় তা CreateThread()হ'ল signal()ফাংশন।

তবে দৃ cons়তার দিক থেকে আমি ব্যক্তিগতভাবে ব্যবহার চালিয়ে যাওয়া পছন্দ করি _beginthreadex()


যদিও আমি এটি সত্য বলে মনে করি, আপনি কি কিছু প্রামাণ্য প্রমাণ সরবরাহ করতে পারেন - হয় এমএস ডকুমেন্টেশনের সাথে সংযুক্তি দিয়ে, বা সিআরটি _বেগিনথ্রেডেক্স / _অ্যান্ডথ্রেডেক্স উত্স বিশ্লেষণ করে?
সুমা

@ সুমা, আমি অনুমান করি যে আপনি মন্তব্যটি লেখার সময় আমি এমএসকে এটি যুক্ত করেছিলাম ;-)
সার্জ ওউটিয়ার

আপনি যে ডকুমেন্টের সাথে লিঙ্ক করছেন সেটি নিশ্চিত হয় না: "তবে, সিআরটি ফাংশনগুলি কী বলা হয় তার উপর নির্ভর করে থ্রেডগুলি বন্ধ হয়ে গেলে একটি ছোট মেমরি ফাঁস হতে পারে" " এর অর্থ এটি এখন আর বড় এবং সাধারণ নো-হ'ল নয়, তবে আপনি যদি ঘন ঘন থ্রেড তৈরি করেন এবং সেগুলিতে এই ফাংশনগুলি ব্যবহার করেন তবে এখনও তা নো-নো। যাইহোক, দস্তাবেজটি ২০০৫ সালের এবং তাই সাম্প্রতিক পরিস্থিতিটির বিষয়টি চিহ্নিত করতে পারে না।
সুমা

1
হুম ... যদিও এটি ব্যবহারের ক্ষেত্রে নির্ভর করবে, একটি ফাংশন যা মেমরি ফাঁস ছেড়ে দেবে না কেন, আকারটি যাই হোক না কেন, আমি একটি নো নম্বর বিবেচনা করব ... - বিশেষত যদি কোনও অ-ফাঁস বিকল্প থাকে!
একেবারে

"সিআরটি না ভেঙে এখনই কেউ ক্রিয়েটথ্রেড () কল করতে পারে।" - দুর্ভাগ্যক্রমে, এটি সত্য নয় এবং কখনও হয়নি। ক্রিয়েটথ্রেড থেকে : "একটি এক্সিকিউটেবলের একটি থ্রেড যা সি রান-টাইম লাইব্রেরি (সিআরটি) বলে ডাকে থ্রেড পরিচালনার জন্য _beginthreadex এবং _endthreadex ফাংশন ব্যবহার করা উচিত [...] যদি ক্রিয়েটথ্রেড ব্যবহার করে তৈরি করা একটি থ্রেড সিআরটি কল করে, সিআরটি সমাপ্ত হতে পারে স্বল্প-স্মৃতি শর্তে প্রক্রিয়া। "
IInspectable

2

CreateThread()উইন্ডোজ এপিআই কলটি ভাষা নিরপেক্ষ। এটি কেবল ওএস অবজেক্ট - থ্রেড তৈরি করে এবং এই থ্রেডটিতে HANDLE প্রদান করে। সমস্ত উইন্ডোজ অ্যাপ্লিকেশন থ্রেড তৈরি করতে এই কলটি ব্যবহার করছে। সমস্ত ভাষা সুস্পষ্ট কারণে সরাসরি এপিআই কল এড়িয়ে চলে: ১. আপনি নিজের কোডটি ওএস নির্দিষ্ট করতে চান না API. এপিআই-এর মতো কল করার আগে আপনার কিছু ঘর রাখা দরকার: প্যারামিটার এবং ফলাফল রূপান্তর করুন, অস্থায়ী সঞ্চয়স্থান বরাদ্দ করুন ইত্যাদি calling

_beginthreadex()CreateThread()যে চারপাশে সি মোড়ক সি নির্দিষ্ট জন্য অ্যাকাউন্ট। এটি থ্রেড নির্দিষ্ট স্টোরেজ বরাদ্দ করে মাল্টিথ্রেড পরিবেশে মূল একক থ্রেডেড সি f-ns কাজ সক্ষম করে।

আপনি সিআরটি ব্যবহার না করলে আপনি সরাসরি কল এড়াতে পারবেন না CreateThread()। আপনি যদি সিআরটি ব্যবহার করেন তবে আপনাকে অবশ্যই ব্যবহার করতে হবে _beginthreadex()বা কিছু সিআরটি স্ট্রিং এফ-এনএস ভিসি 2003 এর পূর্বে সঠিকভাবে কাজ না করতে পারে।


1

CreateThread()সরল সিস্টেম কল। এটি প্রয়োগ করা হয়েছে Kernel32.dllযার উপর , সম্ভবত, আপনার আবেদনটি ইতিমধ্যে অন্য কারণে লিংক করা হবে। এটি সর্বদা আধুনিক উইন্ডোজ সিস্টেমে উপলব্ধ।

_beginthread()এবং _beginthreadex()মাইক্রোসফ্ট সি রানটাইমের ( msvcrt.dll) এ মোড়ক ফাংশনগুলি রয়েছে । দুটি কলের মধ্যে পার্থক্য ডকুমেন্টেশনে বর্ণিত হয়েছে। এটি মাইক্রোসফ্ট সি রানটাইম উপলভ্য হলে বা আপনার অ্যাপ্লিকেশনটি যদি এর বিপরীতে স্ট্যাটিকভাবে লিঙ্ক করা থাকে তখন এটি উপলব্ধ। আপনি সম্ভবত সেই লাইব্রেরির সাথে সংযোগ স্থাপন করবেন, যদি না আপনি খাঁটি উইন্ডোজ এপিআইতে কোডিং করে থাকেন (যেমন আমি ব্যক্তিগতভাবে প্রায়ই করি)।

আপনার প্রশ্ন একটি সুসংগত এবং আসলে একটি পুনরাবৃত্তি। অনেকগুলি এপিআই, উইন্ডোজ এপিআইতে নকল এবং দ্ব্যর্থক কার্যকারিতা রয়েছে যা আমাদের মোকাবেলা করতে হবে। সবচেয়ে খারাপ, ডকুমেন্টেশন বিষয়টি পরিষ্কার করে না। আমি মনে করি যে _beginthread()ফাংশনগুলির পরিবারটি হ'ল ম্যানিপুলেশনের মতো অন্যান্য স্ট্যান্ডার্ড সি কার্যকারিতার সাথে আরও ভাল সংহতকরণের জন্য তৈরি করা হয়েছিল errno_beginthread()এইভাবে সি রানটাইমের সাথে আরও ভাল সংহত করে।

তা সত্ত্বেও, যদি না আপনার ব্যবহারের ভাল কারণ থাকে _beginthread()বা না থাকে তবে আপনার ব্যবহার করা _beginthreadex()উচিত CreateThread(), বেশিরভাগ কারণেই আপনি আপনার চূড়ান্ত সম্পাদনযোগ্য (এবং এমএস সিআরটি-র ক্ষেত্রে এটি কিছুটা গুরুত্বপূর্ণ) in কলটির চারপাশে আপনার কোনও মোড়ানোর কোডও নেই, যদিও এই প্রভাবটি নগণ্য। অন্য কথায়, আমি বিশ্বাস করি যে এটির সাথে লেগে থাকার মূল কারণটি CreateThread()হ'ল _beginthreadex()শুরু করার জন্য কোনও ভাল কারণ নেই । কার্যকারিতা অবিকল বা প্রায় একই রকম।

ব্যবহারের এক ভাল কারণ _beginthread() হবে (যেমন মিথ্যা মনে করা হয়) যে সি ++ বস্তু সঠিকভাবে unwinded / ধ্বংস হবে যদি _endthread()ডাকা হয়।


কোন দ্ব্যর্থক ফাংশন কল করার সুবিধা সব সময়েCreateThreadএকটি থ্রেড তৈরি করার জন্য উইন্ডোজ এপিআই কল। আপনি যদি সিআরটি ব্যবহার করছেন (কারণ আপনি সি বা সি ++ তে প্রোগ্রামিং করছেন), আপনার সিআরটি _beginthread[ex]কলগুলি (যা CreateThreadপ্রয়োজনীয় সিআরটি সূচনা করার পাশাপাশি কল করে) ব্যবহার করে থ্রেড তৈরি করতে হবে create _beginthreadপ্রাক্তন বৈকল্পিকের মধ্যে সর্বাধিক গুরুত্বপূর্ণ পার্থক্য : প্রাক্তন স্থানীয় থ্রেড হ্যান্ডেলের মালিকানা বজায় রাখে, তবে পরবর্তীকর্তা কলারের কাছে মালিকানা প্রেরণ করেন।
IInspectable

Nitpick: msvcrt.dllহয় না সি রানটাইম ডিএলএল! দেখুন ব্লগস.এমএসএন.এম.সাইক্রোসফট.ল্ডনেউথিং
গোবিন্দ

0

অন্য উত্তরগুলি একটি সি রান-টাইম ফাংশন যা উইন 32 এপিআই ফাংশনটিকে আবৃত করে কল করার প্রভাবগুলি নিয়ে আলোচনা করতে ব্যর্থ হয়। ডিএলএল লোডার লকিং আচরণ বিবেচনা করার সময় এটি গুরুত্বপূর্ণ।

থাকুক বা না থাকুক _beginthread{ex}হিসাবে অন্যান্য উত্তরগুলো আলোচনা কোনো বিশেষ সি রানটাইম থ্রেড / ফাইবার মেমরি ব্যবস্থাপনা করে, এটা (অভিমানী গতিশীল সি রান-টাইম লিঙ্ক) একটি ডিএলএল যে প্রসেস এখনো লোড নাও হতে পারে বাস্তবায়িত হয়।

এটি _beginthread*থেকে ফোন করা নিরাপদ নয় DllMain। আমি উইন্ডোজ "AppInit_DLLs" বৈশিষ্ট্যটি ব্যবহার করে একটি ডিএলএল লিখে এটি পরীক্ষা করেছি। _beginthreadex (...)পরিবর্তে কল করার CreateThread (...)ফলে উইন্ডোজের প্রচুর গুরুত্বপূর্ণ অংশগুলি বুটআপের সময় কাজ বন্ধ করে দেয় কারণ DllMainকিছু প্রাথমিককরণের কাজ সম্পাদনের জন্য লোডার লকটি প্রকাশের জন্য প্রবেশকারী পয়েন্ট ডেডলকগুলি অপেক্ষা করে।

ঘটনাচক্রে, এই কারণেই কার্নেল 32.dll এর প্রচুর ওভারল্যাপিং স্ট্রিং ফাংশন রয়েছে যা সি রান- টাইমও করে - DllMainএকই ধরণের পরিস্থিতি এড়াতে এগুলি ব্যবহার করুন।


0

আপনি যদি জেফ্রি রিখর থেকে ডিবাগিং উইন্ডোজ অ্যাপ্লিকেশন বইটি পড়ে থাকেন তবে তিনি ব্যাখ্যা করেছেন যে প্রায় সব ক্ষেত্রেই আপনাকে কল করার _beginthreadexপরিবর্তে কল করতে হবে CreateThread_beginthreadচারপাশে কেবল একটি সরলীকৃত মোড়ক _beginthreadex

_beginthreadexনির্দিষ্ট সিআরটি (সি রানটাইম) ইন্টার্নিয়ালগুলি সূচনা করে যা CreateThreadএপিআই করবে না।

ফলাফল যদি আপনি সিআরটি ফাংশনে কল ব্যবহার না করে CreateThreadAPI ব্যবহার করেন তবে _begingthreadexঅপ্রত্যাশিত সমস্যার কারণ হতে পারে।

রিখটার থেকে এই পুরানো মাইক্রোসফ্ট জার্নালটি দেখুন।


-2

দুজনের মধ্যে আর কোনও তফাত নেই।

মেমরি ফাঁস ইত্যাদি সম্পর্কে সমস্ত মন্তব্য খুব পুরানো <ভিএস ২০০৫ সংস্করণে ভিত্তিক। আমি কয়েক বছর আগে কিছু স্ট্রেস টেস্টিং করেছি এবং এই রূপকথার উত্সাহ দিতে পারি। এমনকি মাইক্রোসফ্ট তাদের উদাহরণগুলিতে শৈলীর মিশ্রণ করে, প্রায় কখনওই _ব্যাগেনথ্রেড ব্যবহার করে না।


ক্রিয়েটথ্রেড : "ক্রিয়েটিথ্রেড ব্যবহার করে তৈরি করা একটি থ্রেড যদি সিআরটি কল করে, সিআরটি কম-স্মৃতি অবস্থায় প্রক্রিয়াটি শেষ করতে পারে।"
IInspectable

সাবেন্সিনটিটির ভিত্তিতে "সিআরটির বহুবিধ সংস্করণ ব্যবহার করা দরকার" আমি ধরে নিয়েছি এটি হ'ল ডকুমেন্টেশন আবর্জনা কারণ এখন আর বহু বছর ধরে ক্রটি সংস্করণ নেই।
লোথার

"আর কোনও মাল্টিথ্রেডেড crt সংস্করণ নেই" - এমএসডিএন দাবি করেছে যে "[টি] তিনি সিঙ্গল-থ্রেডেড সিআরটি আর উপলভ্য নয়।" আপনি দুজনই ঠিক থাকতে পারবেন না। আমিও এখানে এমএসডিএন নিয়ে যাব।
IInspectable

এটি একটি টাইপো ছিল অবশ্যই আমার অর্থ ছিল যে একক থ্রেডড চলে গেছে এবং মাল্ট্রিথ্রেড স্ট্যান্ডার্ড হয়ে গেছে এবং যা গেছে তা থ্রেড ব্যবহার বা না ব্যবহারের মধ্যে পার্থক্য।
লোথার

এটি সত্যিই অদ্ভুত হয়ে উঠছে। আপনি এখন একটি বিবৃতি ব্যবহার করছেন, এটি নিঃসন্দেহে সঠিক ( "সিআরটিটির বহুবিধ সংস্করণ ব্যবহার করা দরকার" ) দাবি করার জন্য যে এই বিবৃতিটি পাশাপাশি ডকুমেন্টেশনের বাকী অংশগুলি খুব সম্ভবত ভুল? নিশ্চিত যে সঠিক শোনাচ্ছে না।
IInspectable
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.