فئة الموضوع في دلفي-(1)
فئة الموضوع في دلفي-(1) رابتور (العمل الأصلي)
الكلمة الرئيسية threadeventcriticalsectionsynchronize
فئات الموضوع في دلفي
Raptors [MentalStudio]
http://mental.mentsu.com
(واحد)
هناك THREAD فئة الخيوط في دلفي المستخدمة لتنفيذ برمجة متعددة الخيوط. تم الانتهاء من المزامنة. ومع ذلك ، فإن هذا ليس برمجة متعددة الخيوط.
الخيط هو في الأساس قطعة رمز يعمل بشكل متزامن في عملية ما. تحتوي العملية على موضوع واحد على الأقل ، ما يسمى الخيط الرئيسي. يمكن أن يكون هناك أيضا خيوط الأطفال متعددة. عند استخدام أكثر من مؤشر ترابط في عملية ، يطلق عليه "متعدد الخيوط".
فكيف يتم تعريف هذا ما يسمى "قطعة من الكود"؟ إنها في الواقع وظيفة أو عملية (لدلفي).
إذا كنت تستخدم Windows API لإنشاء مؤشرات الترابط ، فسيتم تنفيذها من خلال وظيفة API تسمى CreateTheRead ، والتي يتم تعريفها على أنها:
HandleCreateThread (
LPSECURITY_ATTRIBUTESLPTHREADTRIBUTES ،
DWORDDWSTACKSIZE ،
LPTREAD_START_ROUTINELPSTARTADDRESS ،
lpvoidlpparameter ،
DWORDDWCREATIENFLAGS
LPDWORDLPTHREADID
) ؛
معلماتهم كما هو مذكور في أسمائهم ، وهي: سمات مؤشرات الترابط (المستخدمة في تعيين سمات أمان مؤشرات الترابط ضمن NT ، غير صالح تحت 9x) ، وحجم المكدس ، وعنوان البدء ، والمعلمات ، وعلامات الإنشاء (المستخدمة لتعيين مؤشرات الترابط في وقت الإنشاء) ، معرف الخيط ، وأخيرا إرجاع مقبض الخيط. عنوان البداية هو مدخل وظيفة مؤشر الترابط ، وينتهي مؤشر الترابط حتى تنتهي وظيفة مؤشر الترابط.
عملية تنفيذ الخيط بأكمله كما يلي:
نظرًا لأن المعلمات الإبداعية كثيرة وهي واجهة برمجة تطبيقات Windows ، يتم توفير وظيفة ترابط عامة في cruntimelibrary (من الناحية النظرية ، يمكن استخدامها في أي نظام تشغيل يدعم مؤشرات الترابط):
unsignedlong_beginthread (void (_userentry*__ start) (void*) ، unsigned__stksize ، void*__ arg) ؛
توفر Delphi أيضًا وظيفة مماثلة مع نفس الوظيفة:
functionBegInThRead (SecurityAttributes: pointer ؛ stacksize: longword ؛ threadfunc: tthreadfunc ؛ المعلمة: pointer ؛ createflags: longword ؛ varthreadid: longword): integer ؛
وظائف هذه الوظائف الثلاث هي نفسها. الفرق الأكبر بين وظائف الخيط والوظائف العامة هو أنه بمجرد بدء وظيفة مؤشرات الترابط ، تستمر وظائف مؤشرات الترابط الثلاثة ، ويستمر مؤشر الترابط الرئيسي في التنفيذ ، بينما يتم تنفيذ وظيفة مؤشر الترابط في مؤشر ترابط مستقل يستغرق التنفيذ وماذا عند العودة ، لا يهتم الخيط الرئيسي به أو يعرفه.
في ظل الظروف العادية ، بعد إرجاع وظيفة الخيط ، ينتهي مؤشر الترابط. ولكن هناك طرق أخرى:
Windows API:
VoIdexitThread (dworddwexitcode) ؛
cruntimelibrary:
void_endthread (void) ؛
Delphiruntimelibrary:
الإجراءات (exitcode: integer) ؛
من أجل تسجيل بعض بيانات مؤشرات الترابط الضرورية (الحالة/الخصائص ، إلخ) ، سيقوم نظام التشغيل بإنشاء كائن داخلي للمعلومات. ينتهي الموضوع.
على الرغم من أن البرمجة متعددة الخيوط يمكن تنفيذها بسهولة باستخدام API أو RTL (RunTimelibrary) ، إلا أن المعالجة الأكثر تفصيلاً مطلوبة.
من السهل جدًا استخدام هذا الفئة. هذه هي وظيفة مؤشر الترابط ، وهي جزء الكود الذي تم تنفيذه في مؤشر الترابط). للحصول على تفاصيل محددة حول هذا الموضوع ، لن أكررها هنا ، يرجى الرجوع إلى الكتب ذات الصلة.
بعد ذلك في هذه المقالة ، سنناقش كيف تغلف فئة TTREAD المواضيع ، أي أننا سنقوم ببحث متعمق حول تنفيذ فئة TTREAD. لأنه من الأفضل استخدامه فقط إذا فهمت ذلك حقًا.
فيما يلي إعلان فئة TTHERED في DELPHI7 (تناقش هذه المقالة فقط التنفيذ ضمن منصة Windows ، لذلك تتم إزالة جميع التعليمات البرمجية حول جزء نظام Linux):
tthread = فئة
خاص
فاندل: ثاندل ؛
fthreadid: Thandle ؛
fcreatesususeded: منطقية ؛
Ferminated: منطقية ؛
fsuspeded: منطقية ؛
ffreeonterminate: منطقية ؛
ffinished: منطقية ؛
Freturnvalue: عدد صحيح ؛
FonerThing: tnotifyevent ؛
fsynchronize: tsynchronizerecord ؛
ffatalexception: tobject ؛
الإجراءات ؛
classprocedureSynchronize (Asyncrec: psynchronizerecord) ؛
FunctionGetPriority: tthreadPriority ؛
الإجراءات setPriority (القيمة: tthreadPriority) ؛
الإجراءات المعلقة (القيمة: منطقية) ؛
محمية
storeRecheckTherDerror (errcode: integer) ؛ overload ؛
storeRecheckTherTerror (النجاح: منطقية) ؛ الزائد ؛
الإجراءات الإجراءات ؛ الظاهرية ؛
الإجراءات execute ؛ افتراضية ؛ مجردة ؛
الإجراءات synchronize (الطريقة: tthreadMethod) ؛ الحمل الزائد ؛
PropertyReturnValue: integerreadfreturnvaluewritefreturnvalue ؛
propertywerting: booleanreadferminated ؛
عام
ConstructorCreate (CreateSuseSpended: Boolean) ؛
Destructordestroy ؛ تجاوز ؛
الإجراءات
الإجراءات ؛
الإجراءات.
الإجراءات ؛
FunctionWaitfor: Longword ؛
classproceduresynchronize (Athread: tthread ؛ amethod: tthreadmethod) ؛ overload ؛
classprocedurestaticynchronize (Athread: tthread ؛ Amethod: tthreadmethod) ؛
PropertyFatalException: TOBJECTREADFFATALEXCESTION ؛
PropertyFreeOnterminate: BooleAnreadffreeNTerminateWriteFfreeOnTerminate ؛
PropertyHandle: ThandlerEadfhandle ؛
PropertyPriority: tthreadPriorityReadGetPriorityWriteStpriority ؛
PropertySususeded: booleanreadfSususPendedWritesEsSusususeded.
propertythreadid: Thandlereadfthreadid ؛
PropertyOnterminate: tnotifyeventReadFonerMinateWriteFonerTerminate ؛
نهاية؛
فئة TTREAD هي فئة بسيطة نسبيًا في Delphi RTL ، مع عدم وجود العديد من أعضاء الفصل والسمات الفئة بسيطة وواضحة للغاية.
(يتبع)
فئة الموضوع في دلفي-(2)
فئة الخيط في دلفي-(2) رابتور (العمل الأصلي)
الكلمة الرئيسية threadeventcriticalsectionsynchronize
فئات الموضوع في دلفي
Raptors [MentalStudio]
http://mental.mentsu.com
اثنين
الأول هو المنشئ:
constructorTthRead.create (CreateSuseSpended: Boolean) ؛
يبدأ
وراثي
addthread
fsuspeded: = createSuseSpended ؛
fcreatesususeded: = createSususedended ؛
fhandle: = beginThread (nil ، 0 ،@threadproc ، pointer (self) ، create_suspended ، fthreadid) ؛
iffhandle = 0then
RaiseTheRead.createresfmt (sThReadCreateRror ، [syserrormessage (getLasterror)]) ؛
نهاية؛
على الرغم من أن هذا المُنشئ ليس لديه الكثير من التعليمات البرمجية ، إلا أنه يمكن اعتباره الأعضاء الأكثر أهمية لأنه يتم إنشاء مؤشر الترابط هنا.
بعد استدعاء tooject.create من خلال الموروثة ، فإن الجملة الأولى هي استدعاء عملية: AddThread ، رمز المصدر الخاص به على النحو التالي:
الإجراءات ؛
يبدأ
interlockedIncrement (threadcount) ؛
نهاية؛
هناك أيضا إزالة المقابلة:
الإجراءات
يبدأ
interlockedDecrement (threadcount) ؛
نهاية؛
وظيفتها بسيطة للغاية ، وهي حساب عدد مؤشرات الترابط في العملية عن طريق إضافة أو تقليل متغير عالمي. ومع ذلك ، فإن عملية INC/DEC الشائعة المستخدمة هنا ليست عملية INC/DEC شائعة الاستخدام ، ولكن يتم استخدام عملية interlockedIncrement/InterlockedDecrement. ولكن هناك فرق واحد بينهما ، أي ، interlockedIncrement/interlockeddecrement هو آمن الخيط. بمعنى أنه يمكنهم التأكد من أن نتائج التنفيذ صحيحة تحت MultiTreading ، لكن Inc/DEC لا يمكن ذلك. أو من حيث نظرية نظام التشغيل ، هذا زوج من العمليات "البدائية".
خذ الإضافة واحدة كمثال لتوضيح الفرق في تفاصيل تنفيذ الاثنين:
بشكل عام ، هناك ثلاث خطوات بعد تحلل تشغيل واحد إلى بيانات الذاكرة:
1. اقرأ البيانات من الذاكرة
2. أضف بيانات واحدة
3. احفظه في الذاكرة
لنفترض الآن أن عملية إضافة واحدة باستخدام INC في تطبيق ثنائي قد تحدث:
1. سلسلة الرسائل A يقرأ البيانات من الذاكرة (على افتراض أنها 3)
2. الموضوع ب يقرأ البيانات من الذاكرة (أيضًا 3)
3. مؤشر الترابط A يضيف واحد إلى البيانات (الآن هو 4)
4. مؤشر الترابط B يضيف واحد إلى البيانات (الآن هو أيضًا 4)
5. مؤشر ترابط A يخزن البيانات في الذاكرة (البيانات الموجودة في الذاكرة الآن 4)
6. مؤشر الترابط B يقوم أيضًا بتخزين البيانات في الذاكرة (لا تزال البيانات في الذاكرة 4 الآن ، لكن كلا الموضوعين يضيفانها ، والتي يجب أن تكون 5 ، لذلك تظهر نتيجة الخطأ هنا)
لا توجد مشكلة في عملية interlockincrement ، لأن ما يسمى "البدائية" هو عملية غير متقطعة ، أي أن نظام التشغيل يمكن أن يضمن عدم إجراء تبديل مؤشر ترابط قبل تنفيذ "بدائي". لذلك في المثال أعلاه ، فقط بعد أن انتهى الموضوع A من تخزين البيانات في الذاكرة ، يمكن أن يبدأ مؤشر الترابط B في جلب الرقم منه وإضافة عملية واحدة ، مما يضمن أنه حتى في المواقف متعددة الخيوط ، ستكون النتيجة بالتأكيد صحيحة.
يوضح المثال السابق أيضًا حالة "تعارضات الوصول إلى الخيوط" ، وهذا هو السبب في أن المواضيع تحتاج إلى "مزامنة".
الحديث عن التزامن ، هناك إلهاء: لي مينغ ، أستاذ بجامعة واترلو في كندا ، الذي أثار اعتراضات على ترجمة كلمة تزامن كـ "المزامنة" في "تزامن الخيط". معقول جدا. في الصينية ، تعني "التزامن" "يحدث في نفس الوقت" ، في حين أن "مزامنة الخيط" تهدف إلى تجنب مثل هذا "يحدث في نفس الوقت". في اللغة الإنجليزية ، يحتوي المزامنة على معنيين: أحدهما هو التزامن بالمعنى التقليدي (TooccuratTheSametime) ، والآخر هو "التنسيق". يجب أن تشير كلمة المزامنة في "مزامنة مؤشر الترابط" إلى المعنى الأخير ، أي ، "لضمان حافظ مؤشرات الترابط المتعددة على التنسيق وتجنب الأخطاء عند الوصول إلى نفس البيانات." ومع ذلك ، لا تزال هناك العديد من الكلمات التي لا تترجم بدقة في صناعة تكنولوجيا المعلومات. يجب توضيح ذلك.
سأذهب بعيدًا ، وسأعود إلى مُنشئ Tthread.
fhandle: = beginThread (nil ، 0 ،@threadproc ، pointer (self) ، create_suspended ، fthreadid) ؛
هنا نستخدم وظيفة Delphirtl المذكورة أعلاه. المعلمة الثالثة هي وظيفة مؤشر الترابط المذكورة أعلاه ، أي جزء الكود الذي تم تنفيذه في مؤشر الترابط. المعلمة الرابعة هي المعلمة التي تم تمريرها إلى وظيفة مؤشر الترابط ، وهنا كائن مؤشر الترابط الذي تم إنشاؤه (أي الذات). من بين المعلمات الأخرى ، يتم استخدام الخامس لتعيين مؤشر الترابط للتعليق بعد الإنشاء وعدم التنفيذ على الفور (يتم تحديد عمل بدء مؤشر الترابط في البناء اللاحق استنادًا إلى علامة CreateSuspended) ، والسادس هو إعادة معرف مؤشر الترابط.
الآن دعونا نلقي نظرة على جوهر Tthread: وظيفة ThreadProc. ومن المثير للاهتمام ، أن جوهر فئة الخيوط هذه ليس عضوًا في الخيط ، ولكنه وظيفة عالمية (لأن اتفاقية المعلمة لعملية البدء يمكن أن تستخدم الوظائف العالمية فقط). هنا رمزها:
functionThReadProc (الموضوع: tthread): عدد صحيح ؛
var
Freethread: Boolean ؛
يبدأ
يحاول
ifnotThread.LeftThen
يحاول
thread.execute ؛
يستثني
thread.ffatalexception: = quiveExceptionObject ؛
نهاية؛
أخيراً
freethread: = thread.ffreeOnterminate ؛
النتيجة: = thread.freturnvalue ؛
thread.doterminate ؛
thread.ffinished: = true ؛
إشارات
iffreethReadThenthread.free ؛
endthread (نتيجة) ؛
نهاية؛
نهاية؛
على الرغم من عدم وجود كود كبير ، إلا أنه الجزء الأكثر أهمية في THREAD بأكملها لأن هذا الرمز هو رمز يتم تنفيذه بالفعل في مؤشر ترابط. فيما يلي شرح كل خط على حدة للرمز:
أولاً ، الحكم على العلم المنتهية لفئة الخيط. يقوم بشكل أساسي بتنفيذ رمز التنفيذ في الفئة المشتقة.
لذلك ، فإن التنفيذ هو وظيفة مؤشر ترابط في فئة مؤشرات الترابط.
في حالة حدوث استثناء في التنفيذ ، يتم الحصول على كائن الاستثناء من خلال quiveExceptionObject وتخزينه في عضو ffatalexception في فئة مؤشر الترابط.
أخيرًا ، هناك بعض الأعمال النهائية التي يتم تنفيذها قبل انتهاء الخيط. يسجل FreethRead المتغير المحلي إعداد خاصية FreeOnwertinated لفئة مؤشرات الترابط ، ثم يقوم بتعيين قيمة إرجاع مؤشر الترابط على قيمة سمة قيمة إرجاع فئة مؤشرات الترابط. ثم قم بتنفيذ طريقة doterminate لفئة مؤشر الترابط.
رمز طريقة doterminate هو كما يلي:
الإجراءات.
يبدأ
ifassigned (fonterminate) thensynchronize (callonterminate) ؛
نهاية؛
إنه أمر بسيط للغاية ، فهو هو استدعاء طريقة CallOnterminate من خلال المزامنة ، كما أن رمز طريقة CallOnterminate هو على النحو التالي ، وهو ما يلي ببساطة استدعاء الحدث Ontermatin:
الإجراءات.
يبدأ
ifassigned (fonterminate) thenfonerting (self) ؛
نهاية؛
نظرًا لأنه يتم تنفيذ حدث OnTerminate في المزامنة ، فهو ليس رمز مؤشر الترابط بشكل أساسي ، ولكن رمز الخيط الرئيسي (انظر تحليل المزامنة لاحقًا).
بعد تنفيذ OnTerminate ، قم بتعيين العلم المغطى بفئة الخيط إلى True.
بعد ذلك ، قم بتنفيذ عملية signalsyncevent ، ورمزها كما يلي:
الإجراءات
يبدأ
setevent (syncevent) ؛
نهاية؛
إنه أمر بسيط للغاية ، فهو إنشاء حدث عالمي: Syncevent.