در توسینسو تدریس کنید

و

با دانش خود درآمد کسب کنید

IPC (ارتباط میان پردازه ای) در لینوکس - قسمت ششم

2.3. Pipes


فراخوانی Pipe

تابع pipe وسیله ای برای انتقال داده بین دو برنامه فراهم می کند. این تابع به صورت زیر می باشد:

#include <unistd.h>
int pipe(int file_descriptor[2]);

به تابع pipe (یک اشاره گر به) یک آرایه از نوع صحیح فرستاده می شود. تابع این آرایه را با دو توصیف کننده فایل پر کرده و صفر را به عنوان مقدار برگشتی، برمی گرداند. در صورت شکست 1- برگردانده می شود.

توصیف کننده های فایل به طریق خاصی به هم متصل شده اند. هر داده ای که در [file__descriptor[1 نوشته شده است، از طریق [file__descriptor[0 قابل خواندن می باشد. داده ها به صورت اولین ورودی-اولین خروجی پردازش می شوند. به این معنا که اگر بایت های 1، 2 و 3 را در [file__descriptor[1 بنویسید، خواندن از [file__descriptor[0 خروجی 1، 2 و 3 را تولید خواهد کرد.

توجه کنید که در اینجا ما با file descriptor ها (توصیفگرهای فایل) کار می کنیم نه file stream ها، در نتیجه برای دستیابی به داده ها به جای استفاده از fread و fwrite باید از فراخوانی های سیستمی سطح پایین read و write استفاده کنید.

در زیر به طور خلاصه فراخوانی های read و write معرفی شده اند.

()read

پایه ای ترین و متداول ترین مکانیزم مورد استفاده برای خواندن، فراخوانی سیستمی ()read می باشد که به صورت زیر تعریف شده است:

#include <unistd.h>
ssize_t read (int fd, void *buf, size_t len);

هر فراخوانی این تابع len بایت از آفست کنونی فایلی که به وسیله fd به آن اشاره می شود را می خواند. سپس محتویات خوانده شده درون حافظه ای که بوسیله buf به آن اشاره می شود، قرار داده می شود. در صورت موفقیت تعداد بایت های نوشته شده درون buf برگردانده می شود. در صورت بروز خطا، 1- برگردانده می شود. مکان فایل(آفست فایل) هم به اندازه تعداد بایت های خوانده شده، جلو برده می شود.

()write

پایه ای ترین و متداول ترین فراخوانی سیستمی مورد استفاده برای نوشتن، ()write می باشد. ()write مشابه ()read است و به صورت زیر تعریف شده است.

#include <unistd.h>
ssize_t write (int fd, const void *buf, size_t count);

هر فراخوانی این تابع، count بایت از buf را درون فایلی که توصیف کننده فایل fd به آن اشاره می کند، می نویسد. در صورت موفقیت، تعداد بایت های نوشته شده برگردانده شده و همچنین مکان فایل (مکان فعلی فایل - آفست) آپدیت می شود. در صورت بروز خطا 1- برگردانده می شود.


2.4. Named Pipes: FIFOS


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

این کار به وسیله FIFOها که گاهی اوقات به آن ها named pipe هم گفته می شود، انجام می شود. named pipeها با یک نام درون سیستم فایل قرار می گیرند اما رفتاری مشابه پایپ های بدون نام در قسمت قبل دارند.

درون برنامه ها، FIFO به صورت زیر ایجاد می شود

int mknod(const char *filename, mode_t mode);

باز کردن یک FIFO به وسیله دستور open

برای باز کردن یک FIFO یک محدودیت وجود دارد و آن این است که برنامه نباید با تنظیم mode به صورت O__RDRW ، یک FIFO را هم برای خواندن و هم برای نوشتن باز کند. این محدودیت عاقلانه به نظر می رسد، زیرا شما معمولا از یک FIFO تنها برای انتقال داده در یک جهت استفاده می کنید، پس نیازی به تنظیم mode به صورت O__RDRW نیست.

اگر می خواهید در دو جهت داده انتقال دهید، بهتر است از دو FIFO استفاده کنید، و یا به طور صریح جهت جریان داده را با بسته و دوباره باز کردن FIFO تغییر دهید. (البته این کار زیاد متداول نیست)

تفاوت دیگری که در باز کردن یک FIFO با یک فایل عادی وجود دارد در استفاده از open__flag (دومین پارامتر تابع open) با گزینه O__NONBLOCK است. استفاده از این حالت نه تنها باعث تغییر در چگونگی پردازش فراخوانی open می شود، بلکه در نحوه پردازش درخواست های read و write هم تغییر ایجاد می کند.

چهار ترکیب مختلف برای پرچم های O__RDONLY ، O__WRONLY و O__NONBLOCK وجود دارد. حال به ترتیب به هر یک از آن ها می پردازیم.

open(const char *path, O_RDONLY);

در این حالت فراخوانی open بلوکه خواهد شد و تا زمانی که یک پردازه، FIFO مشابه را برای نوشتن باز نکرده است، برنخواهد گشت.

open(const char *path, O_RDONLY | O_NONBLOCK);

در این حالت فراخوانی FIFO موفقیت آمیز بوده و بلافاصله بر می گردد، حتی اگر FIFO توسط پردازه ی دیگری برای نوشتن باز نشده باشد.

open(const char *path, O_WRONLY);

در این حالت فراخوانی open تا زمانی که یک پردازه ی دیگر FIFO مشابه را برای نوشتن باز نکرده باشد، بلوکه خواهد شد.

open(const char *path, O_WRONLY | O_NONBLOCK);

این فراخوانی بلافاصله برمی گردد، اما اگر هیچ پردازه ای این FIFO را برای خواندن باز نداشته باشد، فراخوانی open با 1- برمی گردد و FIFO باز نخواهد شد. اگر پردازه ای FIFO را برای خواندن باز داشته باشد، از توصیفگر فایل برگشتی می توان برای نوشتن در FIFO استفاده کرد.


3. مقایسه روش های IPC


در حافظه اشتراکی پردازها یک فضای آدرس را به اشتراک می گذارند و اعمال خواندن و نوشتن را از طریق فضای آدرس به اشتراک گذاشته انجام می دهند. در این روش پردازه ها خود مسئول همزمان کردن دسترسی به قطعه حافظه اشتراکی هستند اما تبادل پیام مکانیزمی را فراهم می کند که به پردازه ها اجازه برقراری ارتباط و همزمان کردن فعالیت هایشان را بدون به اشتراک گذاری فضای آدرسی مشابه می دهد. همچنین در روش تبادل پیام امکان تبادل اطلاعات در محیط های توزیع شده وجود دارد. روش حافظه اشتراکی تا حدی سریع ترین روش برای ارتباط پردازه ها است، اما راحتی کار با این روش به اندازه بقیه روش ها نیست.

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

نتایج یک تحقیق در مورد کارایی روش های ارتباطات به صورت زیر بوده است:

زمان انتقال اطلاعات در pipe صرف نظر از مقدار داده انتقال داده شده، بدون تغییر باقی می ماند. برای برپاسازی یک پایپ مقداری زمان صرف می شود اما بعد از برپاسازی، زمان مورد نیاز برای انتقال داده صرف نظر از مقدار داده، مشابه هم است. اما با افزایش بایت های انتقالی توسط حافظه اشتراکی، زمان انتقال اطلاعات نیز افزایش می یابد. پس وقتی نیاز به انتقال مقدار زیادی داده داریم، تکنیک خط لوله ترجیح داده می شود. وقتی مقدار داده انتقال داده شده کم تر از 4600 بایت باشد، حافظه اشتراکی مزیت های واضحی را در انتقال اطلاعات با سرعت بالا دارد. اما وقتی مقدار داده ارسالی از 4600 بایت فراتر می رود، این برتری از بین می رود چون در اینگونه موارد برای همزمان کردن دسترسی به قطعه حافظه اشتراکی، باید از ابزار های همزمانی پردازش مانند سمافورها استفاده کنیم؛ در نتیجه کارایی ارتباط در روش حافظه اشتراکی نسبت به خط لوله ضعیف تر می شود.


برای تهیه قسمت های 1 الی 6 از این سری مقالات از مراجع زیر استفاده شده است.

References

1.Silberschatz, Abraham, Galvin, Peter Baer and Gagne, Greg. Operating System Concepts. s.l. : John Wiley & Sons, Inc., 2013. pp. 122-147. 978-1-118-06333-0.

2.Matthew, Neil and Stones, Richard. beginning Linux Programming. 4th. s.l. : Wiley Publishing, Inc., 2008. pp. 526-605. 978-0-470-14762-7.

3.Love, Robert. Linux System Programming. 2nd. s.l. : O’Reilly Media, Inc., 2013. pp. 32-37. 978-1-449-33953-1.


نویسنده: رامین غلامی تقی زاده

منبع: انجمن تخصصی فناوری اطلاعات ایران

هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد

#ارتباط_میان_پردازه_ای #ipc_در_لینوکس
عنوان
1 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت اول رایگان
2 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت دوم رایگان
3 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت سوم رایگان
4 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت چهارم رایگان
5 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت پنجم رایگان
6 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت ششم رایگان
7 IPC (ارتباط میان پردازه ای) در لینوکس - قسمت هفتم رایگان
زمان و قیمت کل 0″ 0
0 نظر

هیچ نظری ارسال نشده است! اولین نظر برای این مطلب را شما ارسال کنید...

نظر شما
برای ارسال نظر باید وارد شوید.
از سرتاسر توسینسو
تنظیمات حریم خصوصی
تائید صرفنظر
×

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