وباکا

آموزش تخصصی برنامه نویسی وب

ایجاد نخ ها(رشته ها-بندها) با کمک کلاس Thread در سی شارپ

برنامه نویسی ناهمزمان و چندرشته ای یک ویژگی مهم برای اشتراک زمانی و پردازش موازی است. برنامه نویسی غیرهمزمان می تواند از چندرشته ای (multithreading) استفاده کند یا خیر. در این آموزش به تعریف پوسس ها، نخ ها و روش کار با نخ ها در زبان سی شارپ می پردازیمتعریف پروسس (Process)

برنامه های کامپیوتر صرفا اجرا پذیر هستند, باینری (یا طور دیگر ), این برنامه ها روی دیسک قرار دارند. اینها نمی توانند کاری انجام بدهند(به اصطلاح مرده هستند) تا زمانی که داخل حافظه بارگذاری شوند و از سیستم عامل درخواست کنند. پروسس یک برنامه در حال اجرا است.
هر پروسس یک ادرس فضا , حافظه و یک پشته داده دارد. سیستم عامل کنترل کننده تمام پروسس های در حال اجرا بر روی سیستم است, و زمان رو میان انها به طور خوب تقسیم می کند. پروسس ها می توانند چند شاخه بشوند یا یک پروسس جدید برای انجام دیگر کارها ایجاد کنند, هر یک از این پروسس های جدید حافظه و پشته داده و… خودشان را دارند.

تعریف نخ (Thread)

 Thread ها یا نخ ها به قطعه کدهایی گفته می شود که به صورت موازی و همزمان با هم اجرا می شوند و به شما این امکان را می دهند برنامه هایی را طراحی و پیاده سازی کنید که می توانند چندین کار را با هم انجام دهند به طور مثال :جستجوی چند فایل یا گرفتن اطلاعات از طریق شبکه و ذخیره انها در دیسک. البته اصولا نخ ها به صورت همزمان اجرا نمی شوند بلکه CPU براساس تنظیم زمان خود یک زمان غیر قابل درک برای انسان را در نظر می گیرد سپس در این مدت زمان یک کار را انجام داده و پس از اتمام این زمان به سراغ کار بعدی می رود به اصطلاح در کارهای خود سوییچ می کند. به این مدت زمان کوتاه اصطلاحا Time Slice یا پرش زمان می گویند.

چند نخی (multi threading)

 multi threading در واقع جدا سازی پردازش ها از یکدیگرست. مثلا در یک برنامه سی شارپ شما به صورت پیش فرض کل برنامه شما در یک نخ اجرا میشود. اگر در این برنامه یک حلقهFor دارید که ممکنست تا بی نهایت طول بکشد، تا زمانی که به اتمام نرسد هیچ کار دیگری نمیتوانید انجام دهید. اما اگه این حلقه را در یک نخ اجرا کنید و بقیه عملیات رادر نخ دیگری، هر دو این عملیات به طور همزمان اجرا میشوند و هیچکدام به دیگری تاثیری نمیگذارد. همچنین استفاده دیگری که multi threadingدارد این است که یک پردازش بزرگ رابه چند پردازش کوچیک بشکنیم و هرکدام رادریک نخ اجرا کنیم که باعث افزایش سرعت میشود. در ضمن هرکدام از نخ ها دچار مشکل شوند و هنگ کنند بقیه ترد ها به کار خود ادامه میدهند.

مزاياي استفاده از Threadها

 ۱ـ به اشتراك‌گذاري منابع پردازشي سيستم بين Threadها.
۲ـ اجراي كارهاي سنگين (مانند ارسال اطلاعات در شبكه، پردازش عكس و…) توسط Threadهاي ديگر باعث مي‌شود Threadاصلي كه UI و برقراري ارتباط با كاربر را انجام مي‌دهد، درگير كارهاي سنگين نشده و باعث هنگ كردن آن نمي‌شود.
۳ـ استفاده از Threadها يك اجراي انتزاعي هم روند را براي اجراي برنامه فراهم مي‌كند.
۴ـ برنامه‌هايي كه از چند Thread استفاده مي‌كنند(Multi Threads Program) در سيستم‌هايي كه چند پردازنده دارد سريع‌تر و راحت‌تر اجرا مي‌شوند.

معايب استفاده از Thread ها

۱ـ كدنويسي شما به عنوان برنامه‌نويس، پيچيده مي‌شود.
۲ـ نياز به تشخيص/ اجتناب/‌ حل مشكلات deadlocks (در مورد deadlock در شماره‌هاي پيش توضيح داده‌ايم) وجود دارد.

3ـ مديريت بيشتر روي خطاهاي مديريت نشده (Unhandled Exception).

کار با Thread ها در c#

 در ابتدا باید یک Object از نوع System.Threading.Thread ایجاد کنید.
کلاس Thread تنها یک ایجادکننده (Constructor) دارد که یک ThreadStart (که یک Delegate است) می گیرد. برای توابع static می توان مستقیما نام تابع را ارسال کرد. تابع نوشته شده باید هیچ پارامتری نداشته باشد و هیچ مقداری را نیز برنگرداند (یعنی void باشد) به این علت که تابع اصلی این گونه تعریف شده است.
بعد از ایجاد Thread می توانید آن را با Start، شروع کنید:

using System;
using System.Threading;
namespace sample1
{
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(DoTask);
}
thread.Start();
}
static public void DoTask()
{
Console.WriteLine("thread created...");
}
}

برنامه زیر بعد از ایجاد نخ، ویژگی های آن را از جمله نام، اولویت (priority) و نوع آن (پیش زمینه یا پس زمینه) را تنظیم می کند.


using System;
using System.Threading;
namespace sample1
{
static void Main(string[] args)
class Program
{
{
Thread thread = new Thread(DoTask);
thread.Name = "My new thread";// Asigning name to the thread
thread.Priority = ThreadPriority.AboveNormal;// Setting thread priority
thread.IsBackground = false;// Made the thread forground
thread.Start();// Start DoTask method in a new thread
Console.WriteLine("thread created...");
//Do other task in main thread
}
static public void DoTask()
{
}
}

مثال زیر نمونه کامل تری از نخ ها را نشان می دهد. یک کلاس دارای دو تابع Thread1 و Thread2 تعریف شده و در برنامه اصلی با ایجاد دو نخ، برای هر کدام یکی از این دو تابع اجرا شده است.


using System;
using System.Threading;
public class MyThread {
public static void Thread1() {
for (int i = 0; i < 10; i++) {
}
Console.WriteLine("Thread1 {0}", i);
}
Console.WriteLine("Thread2 {0}", i);
public static void Thread2() {
for (int i = 0; i < 10; i++) {
}
Console.WriteLine("Before start thread");
}
}
public class MyClass {
public static void Main() {
Thread tid2 = new Thread(new ThreadStart(MyThread.Thread2 ) );
Thread tid1 = new Thread(new ThreadStart(MyThread.Thread1 ) );
tid1.Start();
tid2.Start();
}
}

خروجی این برنامه بصورت زیر است. یعنی هر دو تابع پشت سر هم اجرا شده اند:

Before start thread
Thread1 0
Thread1 1
Thread1 4
Thread1 2
Thread1 3
Thread1 5
Thread1 9
Thread1 6
Thread1 7
Thread1 8
Thread2 0
Thread2 5
Thread2 1
Thread2 2
Thread2 3
Thread2 4
Thread2 6
Thread2 9
Thread2 7
Thread2 8

به جای برنامه فوق می توان از برنامه زیر استفاده کرد:

using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread1 {0}", i);
}
}
public class MyClass {
public void Thread2() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread2 {0}", i);
}
public static void Main() {
Thread tid2 = new Thread(new ThreadStart(thr.Thread2) );
Console.WriteLine("Before start thread");
MyThread thr = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr.Thread1) );
tid1.Start();
tid2.Start();
}
}

در نمونه برنامه زیر کلاس myThread دارای یک تابع بنام Thread1 است و در برنامه اصلی دو نمونه از نوع این کلاس ایجاد شده و برای هر نخ، تابع یکی از این نمونه ها فراخوانی شده است:

using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world {0}", i);
}
}
}
public class MyClass {
public static void Main() {
MyThread thr2 = new MyThread();
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
tid1.Start();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid2.Start();
}
}

در برنامه زیر تابع نوشته شده برای نخ بعد از چاپ یک خروجی به مدت یک میلی ثانیه توقف می کند ، در این فاصله پردازنده به نخ دیگر داده شده و یک خروجی برای او چاپ می کند. به عبارتی پردازنده دائماً بین نخ ها دست به دست می شود.

using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world " + i);
Thread.Sleep(1);
}
}
}
public class MyClass {
MyThread thr1 = new MyThread();
public static void Main() {
Console.WriteLine("Before start thread");
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
tid1.Start();
tid2.Start();
}
}

خروجی حاصل از این برنامه بصورت زیر است:

Before start thread
Hello world 0
Hello world 1
Hello world 0
Hello world 1
Hello world 3
Hello world 2
Hello world 2
Hello world 3
Hello world 5
Hello world 4
Hello world 4
Hello world 5
Hello world 6
Hello world 8
Hello world 6
Hello world 7
Hello world 7
Hello world 8
Hello world 9
Hello world 9

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

فهرست مطالب