رایانش موازی
زمینه > شرایط مسابقه، انحصار متقابل، همگام سازی و کند شدن موازی

وظایف فرعی(subtask) در یک برنامه موازی را اغلب رشته می‌نامند. برخی از معماری‌های موازی رایانه‌ای از نوعی رشته‌های کوچکتر و سبک که به عنوان فیبر معروف هستند استفاده می‌کنند، در حالی که برخی دیگر از رشته‌های بزرگتر به نام پردازش استفاده می‌کنند. با این حال، «رشته‌ها» به‌طور کلی به عنوان یک اصطلاح عمومی برای وظایف فرعی استفاده می‌شود. رشته‌ها اغلب به دسترسی همزمان به یک شی یا منبع دیگر احتیاج دارند؛ برای نمونه وقتی که آنها باید متغیری را که بین آنها به اشتراک گذاشته شده‌است به روز کنند. بدون همگام سازی، دستورالعمل‌های بین دو رشته به هر ترتیب ممکن است در لابلای هم قرار گیرند. برای نمونه، برنامه زیر را در نظر بگیرید:
| 0 | 1 |
| --- | --- |
Thread A: Thread B
1A: Read variable V: 1B: Read variable V
2A: Add 1 to variable V: 2B: Add 1 to variable V
3A: Write back to variable V: 3B: Write back to variable V
اگر دستورالعمل 1B بین 1A و 3A یا دستورالعمل 1A بین 1B و 3B اجرا شود، برنامه داده‌های نادرستی تولید می‌کند. این حالت باعث ایجاد شرایط مسابقه‌ای می‌شود. برنامه‌نویس برای ایجاد انحصار متقابل باید از قفل استفاده کند. قفل یک ساختار زبان برنامه‌نویسی است که به یک رشته اجازه می‌دهد تا کنترل یک متغیر را بدست گرفته و تا زمانی که قفل آن متغیر باز شود از خواندن یا نوشتن در آن توسط سایر رشته‌ها جلوگیری کند. ریسمان نگهدارنده قفل برای اجرای بخش بحرانی آن (بخشی از برنامه که نیاز به دسترسی انحصاری به برخی از متغیرها دارد) و باز کردن قفل داده پس از پایان کارش آزاد است؛ بنابراین، برای تضمین اجرای صحیح برنامه، می‌توان برنامه فوق را برای استفاده از قفل بازنویسی کرد:
| 0 | 1 |
| --- | --- |
Thread A: Thread B
1A: Lock variable V: 1B: Lock variable V
2A: Read variable V: 2B: Read variable V
3A: Add 1 to variable V: 3B: Add 1 to variable V
4A: Write back to variable V: 4B: Write back to variable V
5A: Unlock variable V: 5B: Unlock variable V
یک رشته با موفقیت متغیر V را قفل می‌کند، در حالی که از رشته دیگر ممانعت می‌شود - تا زمانی که قفل V دوباره باز شود نمی‌تواند ادامه دهد. این وضعیت اجرای صحیح برنامه را تضمین می‌کند. در صورتی که نیاز به دسترسی رشته‌ها به منابع بصورت سریالی باشد، ممکن است وجود قفل برای اطمینان از اجرای صحیح برنامه ضروری باشد، اما استفاده از قفل‌ها می‌تواند برنامه را بسیار کند کند و بر قابلیت اطمینان آن تأثیر بگذارد.
قفل کردن متغیرهای متعدد با استفاده از قفل‌های غیر یکجا ممکن است موجب بن‌بست در برنامه شود. یک قفل یکجا (اتمیک) همزمان چندین متغیر را با هم قفل می‌کند. اگر نتواند همه آنها را با هم قفل کند، هیچ‌یک را قفل نمی‌کند. اگر دو رشته بخواهند با استفاده از قفل‌های غیر یکجا دو متغیر مشترک را قفل کنند، ممکن است که یک ریسه یکی از آنها را قفل کند و ریسه دوم متغیر دیگر را قفل کند. در چنین شرایطی، هیچ‌کدام از دو رشته نمی‌تواند کامل شوند و بن‌بست بوجود می‌آید.
در بسیاری از برنامه‌های موازی باید وظایف فرعی به‌طور همگام انجام شود. این امر مستلزم استفاده از مانع(barrier) است. موانع معمولاً با استفاده از قفل یا سمافور اجرا می‌شوند. یک کلاس از الگوریتم‌ها، که تحت عنوان الگوریتم‌های بدون قفل و بدون انتظار شناخته می‌شوند، درکنار هم، از استفاده از قفل و موانع جلوگیری می‌کنند. با این حال، اجرای این روش به‌طور کلی دشوار است و نیاز به ساختارهای داده‌ای دارد که به درستی طراحی شده باشند.
همه موازی‌سازی‌ها منجر به افزایش سرعت نمی‌شوند. به‌طور کلی، با تقسیم وظایف به رشته‌های بیشتر و بیشتر، این رشته‌ها بخشی از زمان فزایندهٔ خود را، صرف برقراری ارتباط با یکدیگر می‌کنند یا منتظر یکدیگر هستند تا به منابع دسترسی پیدا کنند. هنگامی که سربار ناشی از رقابت بر سر منابع یا ارتباطات، بر زمان صرف شده برای محاسبات دیگر غلبه پیدا کند، موازی‌سازی بیشتر (یعنی تقسیم بار کاری بین تعداد بیشتری از ریسه‌ها) موجب افزایش زمان مورد نیاز برای اتمام می‌شود تا کاهش آن. این مشکل که به کند شدن موازی شناخته می‌شود، در برخی موارد با تجزیه و تحلیل و طراحی دوباره نرم‌افزار قابل بهبود است.