المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : الدرس الثامن والأربعون : Multithreading - دورة .net 2008


khaledbelal
02-28-2010, 05:52 PM
بسم الله الرحمن الرحيم .
السلام عليكم ورحمة الله وبركاته .

تعرف نظم التشغيل الحديثة بأنها multitasking systems وهو ما يعني امكانية تنفيذ اكثر من مهمة في نفس الوقت ، لذا تجد أن بامكانك تشغيل عدة برامج في نفس الوقت .

برامج .net من هذا النوع افتراضياً ، لكنك تلاحظ في بعض البرامج ان البرنامج الواحد قادر على تنفيذ اكثر من عملية في نفس الوقت دون أن يكون لهما تأثير متعارض ، هذا ما يعرف باسم multithreading .

لذا تجد ان برنامج الماسنجر يتيح لك ارسال ملفات والحديث واستخدام الكاميرا والتحدث مع اكثر من شخص بنفس الوقت ، وهو ما لم يكن الماسنجر قادراً عليه لو لم يكن يفصل هذه المهام داخل البرنامج الواحد عن بعضها ، هذا هو مضمون درسنا الحالي .

جميع الأوامر التي سنتعامل معها هنا تقع تحت نطاق الأسماء System.Threading ، لذا قم باستيراده أولاً .

العناصر الاساسية داخل مجال الاسماء هذا هي :

Thread : لتعريف Thread جديد والتعامل معه .
ThreadPool : مجموعة من ال Threads يمكن لها التعامل فيما بينها .
ThreadState : Enum يحتوي على عدة حالات لأي Thread .
ThreadStart : بدء التنفيذ في Thread .
ThreadPriority : تحديد اولوية هذا ال Thread .

بالاضافة إلى :

Semaphore
Mutex
Monitor

وهي في الاساس الجوريزمات تستخدم لعمليات التزامن synchronization بحيث لا يسمح لأكثر من Thread بالوصول إلى نفس المصادر في نفس الوقت ، لمزيد من التعرف على هذه الالجوريزمات يمكن البدء من هنا :
http://en.wikipedia.org/wiki/Semaphore_(programming)
http://en.wikipedia.org/wiki/Mutual_exclusion
http://en.wikipedia.org/wiki/Monitor_(synchronization)

System.Threading.Thread

الفئة الاساسية في مجال الاسماء هذا ، تتيح لنا انشاء threads وتنفيذ مهامنا المختلفة عليها ، مكونات هذه الفئة الاساسية هي :

Sleep() : توقف عمل ال thread لفترة من الوقت .
IsAlive : قيمة توضح إذا كان ال thread ما زال يعمل ام لا .
IsBackground : إذا كان ال thread يعمل في background .
Priority : الأولوية الحالية .
ThreadState : حالة ال Thread .
Name : اسم ال thread .
Abort() : خروج .
Join() : توقف عمل ال thread حتى حدوث الحدث في join .
Resume() : استئناف العمل بعد ايقافه .
Start() : بدء العمل للمرة الأولى .
Suspend() : ايقاف العمل مؤقتاً .

سنقوم بداية بعمل تجربة سريعة للاستدلال على معنى ان يتم تنفيذ مهمتين في نفس الوقت ، نعود بعدها لاستئناف شرح المفاهيم الخاصة بالموضوع .

قم بتجربة الكود التالي :

c#:

static void Main(string[] args)
{
order1();
order2();

Console.ReadKey();
}
static void order1()
{
for (int i = 0; i < 100; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}


vb.net:

Private Shared Sub Main(ByVal args As String())

order1()
order2()


Console.ReadKey()
End Sub
Private Shared Sub order1()
For i As Integer = 0 To 99
Console.ForegroundColor = ConsoleColor.Green
Console.Write(i.ToString() + " ")
Next
End Sub
Private Shared Sub order2()
For i As Integer = 100 To 1 Step -1
Console.ForegroundColor = ConsoleColor.Red
Console.Write(i.ToString() + " ")
Next
End Sub



الكود كما هو واضح يقوم بطباعة الأرقام تصاعدياً وتنازلياً ، الناتج الطبيعي هو طباعة التصاعدي ومن ثم التنازلي ، في حين يتم طباعة نتائج الدالة الأولى بالأخضر والثانية بالأحمر للتفريق لتكون شاشة النتائج بالشكل التالي مثلاً :

http://vb4arab.com/vb/uploaded/3/01210265737.jpg

وهذا الطبيعي ، يتم تنفيذ الدالة الأولى حتى الانتهاء ومن ثم الثانية حتى الانتهاء ، أما الآن سنقوم بتعريف threads مختلفة للتنفيذ بحيث يتم تنفيذ كل دالة على واحد منها حيث سيتم تنفيذهم على البروسيسور في نفس الوقت ، الكود التالي مثلاً :

c#:

static void Main(string[] args)
{
System.Threading.Thread t1 = new System.Threading.Thread(order1);
t1.Start();
System.Threading.Thread t2 = new System.Threading.Thread(order2);
t2.Start();
Console.ReadKey();
}
static void order1()
{
for (int i = 0; i < 100; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}



vb.net:

Private Shared Sub Main(ByVal args As String())
Dim t1 As New System.Threading.Thread(order1)
t1.Start()

Dim t2 As New System.Threading.Thread(order2)
t2.Start()

Console.ReadKey()
End Sub
Private Shared Sub order1()
For i As Integer = 0 To 99
Console.ForegroundColor = ConsoleColor.Green
Console.Write(i.ToString() + " ")
Next
End Sub
Private Shared Sub order2()
For i As Integer = 100 To 1 Step -1
Console.ForegroundColor = ConsoleColor.Red
Console.Write(i.ToString() + " ")
Next
End Sub


الآن لنرى طبيعة النتائج .

http://vb4arab.com/vb/uploaded/3/11210265737.jpg

بالطبع النتائج لن تكون كما هي كل مرة ، جرب تغيير ال Priority مثلاً لواحد منهم وجرب النتائج ، ستجد أن صاحب الأولوية الأعلى يتم الانتهاء منه قبل الثاني ، الكود التالي مثلاً :


t1.Priority = System.Threading.ThreadPriority.Highest;


ستصبح النتائج بالشكل التالي :

http://vb4arab.com/vb/uploaded/3/01210265915.jpg



ستجد اختلافات في التنفيذ ، لكن الشاهد هو أن الكودين تم تنفيذهم سوية في هذا الوقت .


بالطبع ليس هذا هو استخدام الوحيد لل threads ، ولكنها كانت فقط مقدمة سريعة . سنعود ونواصل

ال Priority :

تحدد ال Priority أولوية التنفيذ عندما يتم ادخال ال threads على البروسيسور ، حيث ان ال thread ذو الاولوية الأعلى يحظى بعدد مرات تنفيذ ، لتقريب المفهوم نفترض ان لدينا

- مهمة 1 اولوية قصوى .
- مهمة 2 اولوية قصوى .

في هذه الحالة يتم ادخال المهمة 1 للبروسيسور ، ثم 2 ، ثم 1 وهكذا .
أما في حال كون مهمة 2 ذات اولوية اقل ، يكون الأمر بالشكل التالي :
المهمة 1 ، المهمة 1 ، المهمة 1 ، المهمة 2 ، المهمة 1 ، المهمة 1 ، المهمة 1 ، المهمة 2 ... وهكذا حتى الانتهاء من احدهما .

ليس هذا مكان شرح الجوريزمات البروسيسور ، إنما لو أردت الزيادة يمكنك البدء من هنا ، حيث تجد عدة انواع من ال scheduling .
http://en.wikipedia.org/wiki/Scheduling_%28computing%29

نعود مرة أخرى ، لتحديد Priority أي مهمة لدينا نستخدم ال enum التالي :



public enum ThreadPriority
{
AboveNormal,
BelowNormal,
Highest,
Idle,
Lowest,
Normal, // Default value.
TimeCritical
}
ويصبح الكود بالشكل التالي مثلاً :

t1.Priority = System.Threading.ThreadPriority.Highest;


قبل البعد عن المواضيع الاساسية ، لا تنسى ان بامكانك استخدام sleep لايقاف التنفيذ لمدة ، supponse لايقاف مؤقت ... الخ من النقاط التي بدأنا بها شرحنا لهذا الدرس .

ParameterizedThreadStart :

لعلك لاحظت في المثال السابق اننا نمرر الدالة ومن ثم نقوم بعمل start لها لتنفيذها في thread منفصل ، لكن ماذا لو كانت هذه الدالة تستقبل بارميترات ؟

الحل بسيط ، باستخدام ParameterizedThreadStart بالشكل التالي مثلاً :

c#:

Thread t = new Thread(new ParameterizedThreadStart(functionname));
t.Start(parms);


vb.net:

Dim t As New Thread(New ParameterizedThreadStar(functionname))
t.Start(parms)

foreground and background .

هناك نوعان من ال threads :

ForeGround Thread : هذا يعني ان البرنامج لا يمكن ان يغلق حتى يتم الانتهاء من تنفيذ جميع ال foreground threads الموجودة فيه ، النوع الافتراضي لأي thread تقوم بانشاءه هو من هذا النوع .

BackGround Thread : هذا يعني ان البرنامج يمكن ان يتم اغلاقه حتى لو لم يتم تنفيذ كافة ال background threads ، يتم عمله بالشكل التالي مثلاً :

t.IsBackground = true;


الدرس القادم سوف نبدأ في المعاناة رقم 1 مع ال multithreading ، مشكلة التداخل بين المهام وعملية ال Synchronization .

بصراحة كنت انوي كتابة موضوع كامل عن ال Threads Synchronization ، ولكني لم اجد نفسي قادراً على اضافة أي جديد في هذا الموضوع لمقال الاخ محمد سامر سلو على هذا الرابط :

http://vb4arab.com/vb/showthread.php?t=6341

لذا يمكنك متابعة الدرس من هناك ، ثم العودة إلى هنا مرة أخرى .

الدرس الذي بعده كان ايضاً عن ال Threadbool ، موجود هنا أيضا للأخ محمد :
http://vb4arab.com/vb/showthread.php?t=6340

الدرس بالفيجوال بيسك.نت ، إذا كنت ترغب في العرض باستخدام c# يمكنك التحويل من هنا .
http://labs.developerfusion.co.uk/convert/csharp-to-vb.aspx

لذا سآخد راحة اليوم ، نلتقي غداً مع BackgroundWorker وبعدها تعقيب للأخ supersmart .

BackgroundWorker :

تستخدم ال BackgroundWorker لتنفيذ مهمة معينة تأخذ وقتاً طويلاً بعيداً عن المسار الاساسي للبرنامج ، من أمثلة ذلك الدوال الخاصة بالقراءة من web service أو عمليات معالجة الصور او جلب بعض البيانات من كومبيوتر آخر أو تنفيذ عملية بحث ، او اجراء مجموعة من العمليات طويلة الأمد .

ومع أنك كان بإمكانك عمل هذه الدوال عن طريق تنفيذها في thread تقليدي ، إلا أن BackgroundWorker تعطيك مزيد من التحكم ، ببساطة يمكنك اخباره ال بالدالة التي ترغب في تنفيذها ومن ثم تشغيلها عن طريق RunWorkerAsync() ، أخيراً بعد انتهاء التنفيذ يتم تنفيذ حدث RunWorkerCompleted والتي يمكنك فيه مثلاً عرض النتائج بعد انتهاء تنفيذ هذه المهمة .

للبدء بالعمل قم بعمل Windows Form ، قم برسم بعض الادوات ومن ثم ضع زر امر للبدء بتنفيذ المهمة ، واخيراً قم بسحب أداة BackgroundWorker بالشكل التالي مثلاً :

http://vb4arab.com/vb/uploaded/3/01210353005.jpg

أهم دالتين هما هنا DoWork والذي يتم استدعاءه وقت بدء التنفيذ ، والحدث RunWorkerCompleted والذي يتم اطلاقه بعد الانتهاء من التنفيذ بالشكل التالي مثلاً :

C#:

private void ProcessNumbersBackgroundWorker_DoWork(object sender,
DoWorkEventArgs e)
{
}
private void ProcessNumbersBackgroundWorker_RunWorkerCompleted( object sender,
RunWorkerCompletedEventArgs e)
{
}

vb.net :

Private Sub ProcessNumbersBackgroundWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
End Sub
Private Sub ProcessNumbersBackgroundWorker_RunWorkerCompleted( ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
End Sub

لاحقاً يتم البدء بالتنفيذ بالشكل التالي :

ProcessNumbersBackgroundWorker.RunWorkerAsync(args );

حيث يتم تنفيذ الكود الموجود في الحدث DoWork .

والله الموفق ...
والسلام عليكم ورحمة الله وبركاته .

ماريا إسلام
03-03-2011, 06:14 PM
وعليكم الله ورحمة الله وبركااته
،،،
جزاك الله خيرااااا وبارك في مسعاك
ووفقكم لما يحب ويرضاه
دعوااتكم
//