با حمایت ما%۵
تخفیف بگیرد

logo-samandehi

برنامه نويسي اندرويد 9- همزمانی - مقدمات

مقدمه:

برنامه نویسی اعمال همزمان یکی از اساسی ترین و مهمترین ارکان برنامه نویسی است که متأسفانه حتی بسیاری از برنامه نویسان حرفه ای آنرا نادیده می گیرند. چرا که با وجود سرعتهای بالای CPU در سخت افزارهای PC و Notebook نیاز به استفاده از Thread  ها به چشم نمی آید اما یکی از بزرگترین دلایل وجود Hang  و در نتیجه Crash  ها عدم توجه به این تکنیک برنامه نویسی است.

در دستگاه های ضعیفتر نظیر Smart Phone ها استفاده از Thread ها بسیار واجب و ضروری است و حتی برای انجام هر عمل کم زمانبر نیز استفاده از Thread ها اکیداً توصیه می شود.

این قسمت از آموزش بیشتر جنبه تئوری دارد و به آن توجه ویژه داشته باشید چرا که اگر این مفاهیم را مطالعه نکنید مطمئناً در قسمتهای بعد با مشکل جدی مواجه خواهید شد.

توجه داشته باشید که تعاریف زیر در سیستم عامل های مختلف ممکن است متفاوت باشد، اما در وبندوز و android این چنین است.

 

Process چیست:

بطور کلی و عام، یک Process عبارتست از یک قطعه برنامه در حال اجرا، اما با ذکر مثال عبارتست از یک نرم افزار، یک بازی، یک سرویس و مشابه اینها. هر چند که هر کدام از مثالهای بالا می تواند شامل چندین Process باشد اما غالباً در بسیاری از شرایط تعداد آن فقط یکی است.

با زدن کلید Ctrl+Alt+Delete در ویندوز و رفتن به Task Manager، در تب Processes شما لیستی از پروسس های اجرا شده در سیستم عامل ویندوز را در لحظه اجرا می بینید. بعضی از آنها نرم افزارهای شما هستند، بعضی دیگر نرم افزارهای سیستمی، بعضی سرویس و ... می باشند. در این لیست ممکن است چندین Process به یکدیگر متصل شوند ( که همانطور که گفته شد غالباً اینگونه نیست )

برای ساده تر شدن مفهوم اینگونه می گوییم که یک نرم افزار، بازی یا سرویس در اندروید فقط یک Process است.

اهم خواص Process ها عبارتند از:

♦ Process های متفاوت از Memory  های متفاوتی استفاده می کنند.

♦ Process های متفاوت از هر نظر مستقل از یکدیگر عمل می کنند.

♦ Process ها می توانند شامل یک و یا بیشتر Thread باشند.

♦ با خاتمه یک Process، تمامی Thread های آن نیز به ناگاه خاتمه می یابند.

♦ Process ها دارای Stack نیستند و در ساده ترین شرایط تنها Thread آنها دارای Stack است.

 

Thread  چیست:

Thread یک قطعه کوچک اجرایی است که توسط سیستم عامل در زمان مناسب اجرا می گردد. هر Process شامل یک یا بیشتر Thread خواهد بود. به نرم افزارها ( Process ) هایی که دارای بیش از یک Thread هستند، MultiThread  می گویند و می گوییم.

این سئوال پیش می آید که را از ابتدا یک نرم افزار دارای چندین Process نباشد و مفهوم Thread حذف شود. پاسخ آن در تفاوت این دو است:

اهم خواص Thread ها عبارتند از:

♦ Thread ها به تنهایی وجود ندارند و باید Process ـی دربرگیرنده آنها باشد.

♦ Thread ها هم والد ( هم Process ) از یک Memory مشترک استفاده می کنند که آنهم Memory اشغال شونده توسط Process آنهاست

♦ Thread ها چه هم والد، چه غیر هم والد دارای Stack های جدا هستند.

♦ با خاتمه یک Thread تأثیری به سایر Thread ها وارد نمی شود.

♦ Thread ها دیگر نمی توانند در برگیرنده Thread دیگری باشند.

 

Stack  چیست:

به طور کل Stack محلی از حافظه است که data های ارسالی به آن بصورت LIFO - Last In First Out  ذخیره می شود. اما در مورد بحث کنونی ما فضایی ( منحصر به Thread ) از حافظه است که در اختیار Thread مربوطه قرار گرفته و نتایج و اطلاعات Function های در حال اجرا در آنجا ذخیره می گردد. بنابراین هر Thread با توجه به Stack خود می داند که خط کنونی برنامه در حال اجرا، از کجا فراخوانی شده و قرار است به کجا بازگردد. یعنی اگر Function های متوالی اجرا شوند، تا زمانی که از آن Function ها بازگشت داده نشود، اطلاعات مربوط به آن Function از Stack حذف نمی شود و با بازگشت از آن Function این اطلاعات در اختیار Function صدا زننده قرار گرفته و سپس از Stack پاک خواهد شد.

 

نحوه اجرای یک برنامه:

ابتدا یک Process که حتماً یک Thread دارد ایجاد شده و Thread شروع به اجرای دستور العمل های خود می نماید، اگر نیاز باشد که Thread های دیگری تعریف شود، توسط این Thread تعریف شده و دستور اجرای آنها داده می شود اما والد آنها Thread اجرا کننده نیست بلکه Process است. در این شرایط به Thread اصلی که در بدو پیدایش Process وجود داشته است می گوییم Main Thread . در برنامه نویسی اندروید به آن UI Thread هم می گوییم. علت این نامگذاری این است که هر گونه عملی بر روی UI حتماً حتماً باید از روی این Thread اجرا گردد. پس در اندروید Main Thread = UI Thread.

سایر Thread های ایجاد شده هم به موازات سایر Thread ها ( و حتی Thread اصلی ) شروع به فعالیت کرده و دستور العمل های مربوط به خود را اجرا می کنند.

اگر دستگاه مورد اجرا دارای یک CPU باشد، چون یک CPU فقط توان اجرای یک دستور را در هر لحظه داراست، از Thread ـی به Thread دیگر جهتش می کند و به هر Thread سری می زند تا دستور العمل هایش را اجرا کند، بنابراین اجرای آن موازی به نظر می رسد.

اما اگر دستگاه مورد اجرا دارای بیش از یک CPU باشد، اجرای Thread ها بین CPU ها توزیع می شود و همزمانی اجرا معنی نزدیکتری به واقعیت پیدا می کند، چون چند CPU به معنای واقعی می تواند چند دستور را همزمان اجرا کنند.

 

Thread ها چرا استفاده می شود:

از آنجاییکه پاسخ به ورودی های کاربر ( استفاده کننده نرم افزار یا بازی ) نیازمند سرعت است تا نرمی در نرم افزار احساس شود، در غیر این شرایط خواص کیفی نرم افزار یعنی stable ( پایدار ) و smooth ( نرم ) از بین خواهد رفت. شاید بارها با پیام Not Responding در ویندوز مواجه شده باشید که علت برنامه نویسی ضعیف آن نرم افزار است.

پس هر عملی که نیاز به پردازش متوسط به بالا را دارد حتماً در Thread دیگری قرار داده و اجرا خواهیم کرد که Main Thread نسبتاً آزاد باشد و آماده پاسخگویی به درخواست های کاربر و نمایش اطلاعات به کاربر باشد.

 

چگونه مشخص کنیم که کدهای نوشته شده مربوط به کدام Thread است؟

هیچ گونه، کدهای نوشته شده بسته به نوع برنامه نویسی ما می تواند از هر Thread ـی اجرا شود، و اینکه مثلاً بگوییم کدهای این Method حتماً در Thread فلان اجرا خواهد شد کاملاً غلط است، چرا که آن Method ممکن است توسط هر Thread ـی صدا زده شود و آن Thread اجرا کننده آن خواهد بود. پس مکان های Method ها در کد، معین کننده Thread آنها نیست بلکه منطق برنامه آنرا تعیین می کند که منطق را هم خود ما می نویسیم.

 

روشهای استفاده از Thread:

برنامه نویسی Thread ها یا اصطلاحاً Concurrent Programming بسیار پیچیده است و تکنیک های زیادی دارد. با توجه به این که در این موضوع چندین تألیف حدوداً 1000 صفحه ای موجود است، انتظار نداریم حتی 5% آنرا هم بشناسیم. لذا به دو تا از ساده ترین روشهای استفاده از این تکنیک ها که در شرایط حتی پیچیده هم مشکل ما را حل خواهند کرد اکتفا خواهیم کرد.

 

بزرگترین مشکل استفاده از Thread ها:

از آنجاییکه Thread های هم والد همگی از یک Memory مشترک ( Memory قابل اشغال توسط Process ) استفاده می کنند، پس تغییر همزمان این Memory تنها مشکل اصلی استفاده از Thread ها است. به دو مثال رایج از خطاهای ناشی از Thread توجه کنید:

♦بطور مثال اگر یک Thread همزمان دارد یک instance از کلاس را تغییر می دهد ( می نویسد ) و Thread دیگر سعی در خواندن آن داشته باشد، اتفاقات ناگواری پیش خواهد آمد. در این شرایط حتی نیاز است چندین Design Pattern  مناسب پیاده سازی شود.

♦همینطور اگر یک Thread مقداری را تغییر داد و بعد از آن سعی در خواندن آن داشت، ممکن است به داده درستی نرسد. چون در حد فاصل بین نوشتن و خواندن توسط این Thread ممکن است Thread دیگری آنرا تغییر داده باشد.

بنابراین در برنامه نویسی Thread ها دیباگ کردن بسیار بسیار دشوار و گاه غیرممکن است، لذا بهتر است چیزی ننویسیم که باگ داشته باشد تا اینکه سعی در دیباگ آن داشته باشیم.

 

مثل مفهومی: ( بسیار مهم و کاربردی )

برای سادگی کار و تعبیر مناسبی از Thread ها یک شبیه سازی با دنیای واقعی انجام می دهیم. در این شبیه سازی هر اتفاقی که برای مثل ما می افتد، برای Thread هم خواهد افتاد. پس آنرا به دقت بر مفهوم Thread ها منطبق کنید:

یک کارگاه و کارگرهایش را در نظر بگیرید. در این شرایط:


تعاریف:

♦ فضا و منابع کارگاه = Memory اختصاص یافته به Process

♦ ابزار کارگاه = متغیر های تعریف شده در Memory

♦ کارگرها = Thread های موجود در Process

♦ سرکارگر = Main Thread که وظیفه پاسخگویی به ارباب رجوع را دارد.

♦ کاغذهای دستور العمل = Runnable ها ( در قسمت بعدی آموزش بکار گرفته می شوند )

♦ محصول کارگاه = نرم افزار
 

مصادیق:

♦ فضای کارگاه محدود است همانطور که Memory قابل استفاده برای یک Thread محدود است.

♦ همانطور که ممکن است در یک کارگاه، کارگری ابزاری را اشغال کند، سایر کارگران نمی توانند از آن استفاده کنند تا آن ابزار آزاد شود، همانطور که از یک متغیر تحت تغییر یک Thread نمی توان استفاده کرد مگر اینکه آن Thread نوشتن روی متغیر را رها کند.

♦ همانطور ممکن است یک دستور العمل توسط چند کارگر مورد اجرا قرار گیرد، همانطور که یک Method می تواند توسط چند Thread اجرا شود.

♦ با نبود یک Thread وظیفه تولید محصول بر دوش سایر Thread ها خواهد افتاد اما وظیفه آنها دگرگون نمی شود، همانطور که اگر Thread ـی جدا تعریف نشود وظیفه انجام دستور بر عهده Thread های دیگر و در بدترین شرایط بر عهده Main Thread ( سرکارگر ) است.

♦ هر کارگر در ذهن خود می داند که چه کار می کند و به کار دیگر کارگران کاری ندارد، همانطور که هر Thread ، دارای Stack مخصوص به خود است.

♦ دستور العمل ها بر روی دیوار قرار گرفته، همانطور که در کد در یک جای خاص به اسم Runnable نگه داری می شود، پس در اشغال کسی نیست و هر کسی بخواهد یک نسخه از روی آن برای خود می نویسید همانطور که یک Instance از Runnable ها گرفته خواهد شد ( آموزش جلسه بعد )

♦ محصول هم نتیجه اعمالی است که تمام کارگران با هم انجام داده و محصولی ارائه می دهند، همانطور که Software نتیجه پردازش همه الگوریتم های مورد نیاز است.

و هر چیز دیگری که شما از کارگاه و کارگر به نظرتان می رسد با مصداق بالا کاملاً منطبق با Thread خواهد بود.

 

توصیه ها:

- مثال کارگاه و کارگر را در ذهن خود بررسی کنید و به مطرح کردن سئوالات بیشتر از خود سایر مصادیق آنرا بیابید.

 

مطالب مرتبط

آخرین شرکتهای طرف قرارداد

دارولند

طراحی فروشگاه اینترنتی

آف مکس

طراحی سایت تخفیف گروهی

نمایندگان بیمه ما

طراحی وب سایت و پورتال نمایندگان

پژند الکترونیک

طراحی وب سایت و پرتال

نمایندگی بوش

طراحی وب سایت شرکتی

ایران بزرگ

طراحی وب سایت، اتوماسیون اداری و خدمات شبکه پایگاه خبری ایران بزرگ

ستون فقرات تهران

طراحی پورتال تخصصی پزشکی ستون فقرات تهران

آخرین توییت ها

آخرین مقالات آموزشی

استفاده از تکنولوژی روز دنیا در شرکت فناوران راتا رایان