موضوع مقاله: مسئله تولیدکننده-مصرف‌کننده | مخاطب: عمومی | لحن: دانشنامه‌ای | ساختار: عنوان، مقدمه، 3 بخش، جمع‌بندی | مقاله: | # مسئله تولیدکننده-مصرف‌کننده | مقدمه: در علوم کامپیوتر تولیدکننده-مصرف‌کننده یا همان مسئله بافر محدود یک مثال کلاسیک از مشکل همگام سازی چند پروسه‌ای است. | ## بخش 1: مسئله تولیدکننده-مصرف‌کننده | در اولین نسخه مسئله، دو پروسه سیکلی وجود داشت با نام‌های تولیدکننده و مصرف‌کننده که یک بافر مشترک با اندازه ثابت را به شکل یک صف به اشتراک می‌گذارند. مصرف‌کننده به‌طور مکرراً داده را از بافر می‌خواند و پس از خواندن آن را حذف می‌کند و از این داده به شیوه ای استفاده می‌کند. در اولین نسخه مسئله که دارای یک بافر نامحدود بود، مسئله این بود که چگونه یک کد تولیدکننده و مصرف‌کننده طراحی کنیم به گونه ای که در تبادل داده بین آن‌ها، هیچ داده‌ای از بین نرود یا تکراری نشود و نیز داده توسط مصرف‌کننده به ترتیبی خوانده شود که توسط تولیدکننده نوشته شده‌است، و هر دو پروسه حداکثر پیشرفت ممکن را داشته باشند. در فرمول بندی بعدی مسئله، آقای دیکسترا تولیدکننده‌ها و مصرف‌کننده‌های متعددی را پیشنهاد کرد که مجموعه متناهی از بافرها را به اشتراک می‌گذارند. این کار باعث ایجاد مشکلی دیگر شد و آن این بود که چگونه تولیدکننده‌ها را از نوشتن در بافرهایی که تماماً پر هستند بازداریم و چگونه مصرف‌کننده‌ها را از خواندن بافر، در زمانیکه تمام بافرها خالی هستند بازداریم. اولین موردی که باید در نظر بگیریم این است که یک تولیدکننده و یک مصرف‌کننده و یک بافر با اندازه متناهی وجود داشته باشد. اگر بافر پر باشد، برای تولیدکننده دو راه حل وجود دارد: یا به حالت خواب برود یا اینکه داده را دور بریزد. در زمان بعدی که مصرف‌کننده یک آیتم را از بافر برمی‌دارد، به تولیدکننده اطلاع می‌دهد تا مجدداً شروع به پرکردن بافر کند. در زمان بعدی که تولیدکننده داده را در داخل بافر قرار می‌دهد، مصرف‌کننده را از خواب بیدار می‌کند. این راه حل با استفاده از ارتباطات بین پروسه ای که معمولاً از سمافورها استفاده می‌کنند، میسر است. | ## بخش 2: مسئله تولیدکننده-مصرف‌کننده | اگر راه حل ناکافی باشد، می‌تواند منجر به بن‌بست شود که در این حالت هر دو پروسه منتظرند تا از خواب بیدار شوند. پیاده‌سازی ناکافی برای حل مسئله این وسوسه وجود دارد که از راه حل زیر استفاده کنیم. سناریوی زیر را در نظر بگیرید: مصرف‌کننده همین الان متغیر itemcount را خوانده‌است و متوجه شده‌است که مقدار آن صفر است و می‌خواهد به داخل بلوک if وارد شود. درست قبل از فراخوانی sleep، مصرف‌کننده دچار وقفه می‌شود و تولیدکننده از سر گرفته می‌شود. از آنجایی که قبل از آخرین وضعیت بافر خالی بود، تولیدکننده سعی می‌کند تا مصرف‌کننده را از خواب بیدار کند. زمانیکه مصرف‌کننده از سر گرفته می‌شود مجدداً به خواب می‌رود و دیگر هیچ وقت بیدار نخواهد شد. تولیدکننده تا زمانی که بافر پر شود وارد حلقه می‌شود و بعد از آن وی نیز به خواب می‌رود از آنجایی که هردو پروسه برای همیشه به خواب می‌روند، به‌ناچار، وارد یک بن‌بست می‌شویم؛ بنابراین این راه حل نامطلوب است. یک آنالیز دیگر این است که اگر زبان برنامه‌نویسی پروتکل های(semantic) دستیابی‌های همزمان به متغیرهای مشترک (در این مورد itemcount) با استفاده از همگام سازی را تعریف نکرده باشد، آنگاه راه حل مورد استفاده به همین دلیل نامطلوب خواهد بود و نیازی به اثبات آشکار یک شرایط رقابتی نیست. استفاده از پرچم‌ها (سمافر) سمافرها مشکل از دست رفتن فراخوانی بیدار کردن را حل می‌کنند. زمانی که چندین تولیدکننده داشته باشیم که فضای حافظه یکسانی را در اشتراک داشته باشند، یا چندین مصرف‌کننده داشته باشیم که فضای حافظه یکسانی در اشتراک داشته باشند، این راه حل دارای شرایط رقابتی جدی است که می‌تواند منجر به این شود که دو یا بیش از دو پروسه به‌طور همزمان در یک درگاه (slot) بنویسند یا بخوانند. | ## بخش 3: مسئله تولیدکننده-مصرف‌کننده | این تابع می‌تواند حاوی دو عمل باشد، یکی برای تعیین درگاه موجود بعدی و دیگری برای نوشتن در داخل آن. اگر تابع را بتوان به‌طور همزمان توسط چندین تولیدکننده اجرا کرد آنگاه سناریوی زیر محتمل است: دو تولیدکننده emptycount را کاهش می‌دهند. دومین تولیدکننده درگاه خالی بعدی را مشخص می‌کند و نتایج مشابهی با تولیدکننده اول به دست می‌آورد. به بیان دیگر، ما نیاز به روشی برای اجرای یک ناحیه بحرانی با انحصار متقابل داریم. در اینجا، مهم است که بدانیم، گرچه به نظر می‌رسد که mutex به شکل یک سمافور با مقدار ۱ عمل می‌کند (سمافور باینری)، اما تفاوت در این است که mutex دارای ماهیت مالکیت است. مالکیت به این معنی است که mutex را می‌توان فقط توسط همان پروسه ای که آن را به مقدار صفر کاهش داده‌است، به مقدار یک افزایش داد، و تمام عمل‌های دیگر منتظر می‌مانند تا زمانیکه میوتکس برای کاهش یافتن موجود شود (در واقع به این معنی است که منبع موجود است)، درنتیجه، قطعاً انحصار متقابل بوجود می‌آید و از بن‌بست پیشگیری می‌شود. در نتیجه استفادهٔ نادرست از mutexها می‌تواند، در زمانیکه دسترسی انحصاری لازم نیست، باعث متوقف شدن بسیاری از پروسه‌ها شود، اما mutex به جای سمافور استفاده می‌شود. استفاده از مانیتورها شبه کد زیر یک راه حل را برای مسئله تولیدکننده- مصرف‌کننده با استفاده از مانیتورها نشان می‌دهد. از آنجایی که انحصار متقابل در رابطه با مانیتورها به صورت غیر مستقیم وجود دارد، تلاش اضافه برای محافظت ناحیه بحرانی لازم نیست. به عبارت دیگر، راه حلی که در زیر نشان داده شده‌است با هر تعدادی از تولیدکننده‌ها و مصرف‌کننده‌ها و بدون هیچگونه تغییراتی جواب می‌دهد. | ## جمع‌بندی | لازم است ذکر شود، هنگامیکه یک برنامه‌نویس کدی را می‌نویسد و از مانیتورها استفاده می‌کند در مقایسه با زمانی که از سمافوره‌ها استفاده می‌کند، شانس به وجود آمدن شرایط رقابتی کمتر است.