معهد دعم اتش فى اى بى اس لحلول الويب - Powered by vBulletin


 
 
النتائج 1 إلى 1 من 1

الموضوع: أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا

  1. #1
    عضو جديد


    تاريخ التسجيل: Jun 2011
    رقم العضوية: 7
    المشاركات: 2,181
    HVIPS5 غير متواجد حالياً

    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا


    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا
    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا
    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا

    برمجة متعددة ال Threads
    Multiple Thread Programming

    الحتوى:



    • مفاهيم
    • إنشاء ال Thread
    • إيقاف/إستئناف تنفيذ ال Thread
    • إنهاء ال Thread
    • البرنامج



    1. مفاهيم

    يدعم نظام التشغيل Windows خاصية تشغيل أكثر من برنامج وهو ما يدعى بـ "تعدد المهام" (MultiTasking). عند تشغيل برنامج، يقوم Windows بإنشاء عملية (Process) من خلال حجز فضاء في الذاكرة و تخطيط الملف في ذاك الفضاء ثم يقوم بإنشاء Thread أولي (Primary Thread) حيث يقوم هذا الأخير بتنفيذ كود البرنامج تعليمة بتعليمة.

    يوفّر لنا Windows دوال إنشاءThread من داخل برنامجنا جيث يمّكننا هذا من تنفيذ أكثر من كود في نفس الوقت. يسمى هذا "برمجة متعددة ال Thread". يمكننا أخذ هذا النوع من البرمجة على أنه "برمجة متعددة المهام" حيث يمكن لبرنامجنا تنفيذ أكثر من مهام في نفس الوقت.

    على سبيل المثال، تقوم برامج معالجة النصوص بإستقبال مدخلات من لوحة المفاتيح و في نفس الوقت تقوم بكشف أخطاء النحو إلى غير ذلك. و ذلك لأنها تستعمل أكثر من Thread لتنفيذ أكثر من مهام في نفس الوقت.

    ملاحظة: مازلت أبحث عن تعريب المصطلح "Thread" و ذلك لأننا متقدمون كثيرا في عالم البرمجة نقره لتكبير أو تصغير الصورة ونقرتين لعرض الصورة في صفحة مستقلة بحجمها الطبيعي

    2. إنشاء ال Thread

    تمّكننا الدالة CreateThread من إنشاء Thread و ذلك من خلال تحديد عنوان بداية الكود و هو عنوان أي دالة تستقبل بارامتر واحد من نوع كلمة مضاعفة (DWORD).

    CreateThread: دالة تنشأ Thread

    كود:
    CreateThread PROTO lpThreadAttributes:DWORD,\
                       StackSize:DWORD,\
                       lpStartAddress:DWORD,\
                       pParameter:DWORD,\
                       CreationFlags:DWORD,\
                       pThreadId:DWORD


    • lpThreadAttributes: مؤشر إلى البنية SECURITY_ATTRIBUTES. لانحتاجه -نمرر NULL-
    • StackSize: نحدد عدد بايتات مكدس ال Thread. نستطيع تمرير NULL لكي تأخذ الدالة نفس حجم ال Thread الأولي
    • lpStartAddress: مؤشر إلى عنوان الدالة
    • pParameter: نحدد البرامتر الذي نريد تمريره إلى الدالة.
    • CreationFlags: نمرر 0 إذا كنا نريد تنفيذ الدالة فوريا، أو القيمة CREATE_SUSPENDED ليتم إنشاء ال Thread و تعليقه إلى أن نستدعي الدالة ResumeThread لإستئناف عمل الدالة
    • pThreadId: مؤشر إلى كلمة مضاعفة لترجع فيها الدالة معرّف ال Thread



    القيمة المرجعة: إذا نجحت الدالة، سيحتوي المسجل EAX على مقبض ال Thread. و إذا فشلت الدالة سترجع NULL

    مثال:


    كود:
    ......
    .IF AX==IDM_CREATETHREAD
    MOV EAX,offset ThreadFunc
    invoke CreateThread,NULL,NULL,EAX,0FFFh,0,addr ThreadID
    ......
    ThreadFunc PROC MilliSecond:DWORD
                     invoke Sleep,MilliSecond
                     invoke MessageBox,NULL,addr MsgBoxText,addr MsgBoxCaption,MB_OK
                     RET
    ThreadFunc ENDP

    ملاحظة: تقوم الدالة Sleep بتوقيف تنفيذ Thread لمدة زمنية معينة تحدد بالوحدة جزء من ألف من ثانية

    3. إيقاف/إستئناف تنفيذ ال Thread

    SuspendThread: دالة تمّكننا من إيقاف Thread من خلال تمرير مقبضه

    كود:
    SuspendThread PROTO hThread:DWORD

    القيمة المرجعة: إذا فشلت الدالة سترجع القيمة 0FFFFFFFFh في المسجل EAX

    ResumeThread: دالة تقوم بإستئناف تنفيذ ال Thread من خلال تمرير مقبضه

    كود:
    ResumeThread PROTO hThread:DWORD


    . إنهاء ال Thread

    يوّفر لنا نظام التشغيل Windows العديد من الدوال التي تنهي ال Thread

    ExitThread: ليقوم ال Thread بإنهاء نفسه


    كود:
    ExitThread PROTO ExitCode:DWORD

    ExitProcess: دالة تقوم بإنهاء برنامج و كل ال Threads التي أنشئها



    كود:
    ExitProcess PROTO ExitCode:DWORD

    TerminateThread: لإنهاء Thread من خلال مقبضه


    كود:
    TerminateThread PROTO hThread:DWORD,\
                          ExitCode:DWORD

    TerminateProcess: لإنهاء عملية و كل ال Threads التي أنشئها من خلال مقبض العملية


    كود:
    TerminateProcess PROTO hProcess:DWORD,\
                           ExitCode:DWORD

    ملاحظة:
    عند نجاح الدالة TerminateProcess أو TerminateThread سيحتوي المسجل EAX على قيمة مخالفة للصفر
    يمكننا الحصول على البارامتر ExitCode من خلال إستدعاء الدالة GetExitCodeThread التي تأخذ بارامترين الأول مقبض ال Thread و الآخر مؤشر إلى متغير من نوع DWORD لترجع فيه كود الخروج

    5. البرنامج

    فكرة البرنامج
    لنرى الفرق بين عملية تملك Thread واحد و أخرى تملك أكثر من Thread، سنكتب برنامج يحتوي على قائمة منسدلة "Thread" تتكون من العناصر التالية:

    • "رسالة من الـ Thread": تقوم بإنشاء Thread ينام عدة ثواني بإستعمال الدالة Sleep ثم يظهر لنا رسالة
    • "إنهاء الـ Thread": لإنهاء الـ Thread إن كان يشتغل. إن لم يكن هناك Thread يشتغل يكون هذا العنصر غير فعّال
    • "رسالة": نستدعي الدالة Sleep عدة ثواني ثم يظهر رسالة. -من دون إنشاء Thread
    • "خروج": لإنهاء البرنامج


    شرح البرنامج

    كود:
    .IF    uMsg==WM_CREATE
           invoke CreateStatusWindow,WS_CHILD or WS_VISIBLE,NULL,\
                   hWnd,StatusID
            invoke SetDlgItemText,hWnd,StatusID,addr TerminateMsg

    عند إستقبال الرسالة WM_CREATE نستعمل الدالة CreateStatusWindow لإنشاء "شريط حالة". ثم نضع في الحالة "متوقف" باستعمال الدالة SetDlgItemText


    كود:
    .IF ax==IDM_RUNTHREAD
        mov eax,offset ThreadFunc
        invoke CreateThread,NULL,NULL,eax,hWnd,\
                            NULL,addr ThreadID
        mov hThread,eax
        invoke EnableMenuItem,hMenu,IDM_KILLTHREAD,MF_ENABLED
        invoke SetDlgItemText,hWnd,StatusID,addr RunMsg

    عند إختيال العنصر "رسالة من الـ Thread" نقوم أولا بتحديد عنوان الدالة التي نريد تشغيلها. ثم نمرر هذا العنوان إلى الدالة CreateThread. بعد الرجوع من الدالة نحفظ مقبض المرجع في المتغير hThread ثم نفعّل العنصر "إنهاء الـ Thread" و نضع النص "يشتغل" في شريط الحالة


    كود:
    .ELSEIF ax==IDM_KILLTHREAD
            invoke GetExitCodeThread,hThread,addr ExitCode
            invoke TerminateThread,hThread,ExitCode
            invoke EnableMenuItem,hMenu,IDM_KILLTHREAD,MF_GRAYED
            invoke SetDlgItemText,hWnd,StatusID,addr TerminateMsg

    عند الضغط على "إنهاء الـ Thread" يقوم البرنامج بجلب كود الخروج لتمريره إلى الدالة TerminateThread التي تنهي Thread. نستعمل الدالة EnableMenuItem لترميد -تعطيل- العنصر "إنهاء الـ Thread" ثم وضع النص "متوقف" في شريط الحالة


    كود:
    .ELSEIF ax==IDM_MSG
            invoke Sleep,0FFFh
            invoke MessageBox,NULL,addr MSG2,addr MsgCap2,MB_OK or MB_RTLREADING or MB_RIGHT

    عند الضغط على العنصر "رسالة"، نستعمل الدالة Sleep "لتنويم" البرنامج عدة ثواني ثم إظهار رسالة


    ملاحظة: الأسلوبين MB_OK و MB_RTLREADING لإظهار محتوى الرسالة من اليمين إلى اليسار -لقراءة الرسائل باللغة العربية-

    كود:
    ThreadFunc proc ThWnd:DWORD
               invoke Sleep,0FFFh
               invoke MessageBox,NULL,addr MSG1,addr MsgCap1,MB_OK or MB_RTLREADING or MB_RIGHT
               invoke EnableMenuItem,hMenu,IDM_KILLTHREAD,MF_GRAYED
               invoke SetDlgItemText,ThWnd,StatusID,addr TerminateMsg
               ret
    ThreadFunc endp

    هذه الدالة سيقوم بتنفيذها الـ Thread و هي تقوم بتويمه لعدة ثواني ثم إظهار رسالة، و بعد ذلك تقوم بترميد العنصر "نهاء الـ Thread". ثم تضع النص "متوقف" في شريط الحالة.

    ملاحظة: الفرق بين إستدعاء الرسالة بطريقة عادية و إستعمال الـ Thread هو أنه في حالة إستعمال ال Thread، و أثناء وقت التنويم يمكنك التواصل مع النافذة كإختيار عنصر من القائمة، تكبير أو تصغير حجم النافذة. بينما في الحالة الأخرى عليك الإنتضار إلى أن تظهر الرسالة و تعدها يمكنك التواصل مع النافذة و هذه هي خاصية إستعمال أكثر من Thread.


    التحميل من المرفقات

    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا
    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا
    أسمبلي 32بت: برمجة متعددة ال Threads لنتعلم معا

    الملفات المرفقة
    التعديل الأخير تم بواسطة HVIPS5 ; 06-29-2011 الساعة 02:06 PM

 

ضوابط المشاركة

  • لا تستطيع إضافة مواضيع جديدة
  • لا تستطيع الرد على المواضيع
  • لا تستطيع إرفاق ملفات
  • لا تستطيع تعديل مشاركاتك
  •