تبليغاتX
آموزش و ترفندهای لینوکس ردهت 9
برنامه نویسی Pipe در گنو/لینوکس (قسمت اول)
pipe یک ابزار ارتباطی است کــه امکان ارتباطات یک طرفه را فراهم می*سازد. داده هایی کــه در طـــرف نــوشتنی pipe نوشته می*شوند از طرف دیگر آن که طرف خواندنی نامیده می*شود قابل خواندن است. در واقـــع شمـا باید لولـه*ای را در نظـــر بگیرید که ارتباط دیتا بین دو ناحیه از طریق آن صورت می*پذیرد. ایــن لــولــه داده*ها را بـــه همـان ترتیبی که دریافت می*کند، به ناحیه ی دیگر منتقل می*کند، از این رو از آن به عنوان یک وسیله ی سریال یا ترتیبی یاد می*شود. استفاده از pipe برای ایجاد ارتباط بین دو نخ در یک پروسه یا ارتباط بین پروسه پدر و پروسه فرزند ،*صورت می*پذیرد.
در پوسته*های فرمان، نشانه*ی | یک pipe ایجاد می*کند. مثلاً دستور زیر باعـــث ایـجاد دو پروسه ی فرزند می*شود؛ یکی برای ls و دیگری برای less:
$ ls | lessفرمان بالا همچنین یــک pipe برای مرتبط کردن خـــروجـی استاندارد پروسه ی فرزند ls به ورودی استاندارد پروسه فرزند less ایجاد می*کند؛ نام فایل های لیست شده توسط ls، بــه less فرستاده می*شود، بــه تــرتیبی کــه انـگار مستقیماً به ترمینال فرستاده شده*اند.
ظرفیت یک pipe برای داده*ها محدود است. اگر پروسه*ای کـــه دیـتــا را درون pipe می*نویسد با نرخی سریع تر از پروسه ای کــه دیتا را از pipe می*خواند عمل کند و در صورتی که pipe ظــرفیت نگهداری دیتای بیشتر نداشته باشد، پـروسه ی دیتا نویس تا زمانی که ظرفیت بیشتر آزاد شود، مسدود یا به اصطلاح بلوکه می*شود.
در صورتی که پروسه ی دیتا خوان درون pipe دیتایی برای خواندن نیابد ، مسدود میشود تا این که بالاخره دیتایی فراهم شود ؛ در نتیجه pipe باعث هم روند شدن دو پروسه می*شود . (Synchronization) .ساختن pipe هابرای ساختن pipe از دستــور pipe استفاده کنید. یــک آرایه با اندازه ۲ از نوع عدد صحیح هــم فـراهم کنید. دستور pipe شاخص فایل خواننده را در محل صفر و شاخص فایل نویسنده را در محل شماره یک آرایه ذخیره می*کند. بـرای مثال، کــد زیر را در نظر بگیرید:

int pipe_fds[2]; int read_fd; int write_fd; pipe (pipe_fds); read_fd = pipe_fds[0]; write_fd = pipe_fds[1];
دیتای نوشته شده به شاخص فایل read_fd ، از شاخص فایل write_fd قابل باز خوانی است.
بر قراری ارتباط بین پروسه پدر و فرزندفـــراخــوانی pipe در یک پروسه ، شاخص*های فایلی ایجاد می*کند کــه فقط مابین آن پروسه و فرزندانش معتبر هستند. شاخص*های فایل یک پروسه قابل فرستادن بـــه پروسه*های نامــربوط نیست. امـا وقتی که یک پروسه fork را فراخوانی می*کند، ایـن شاخص ها برای فرزندان جدید پروسه کپی می*شود. در نتــیجه pipe فقط می*تواند پروسه های مربوط را به هم وصل کند.
در نمونه برنامه ۱، fork پروسه فرزند جـــدیدی ایجاد می*کند؛ فرزند جدید، شاخص های فایل را از پدر به ارث می*برد . پدر رشته ای از کاراکتر ها را توی pipe می*نویسد و فرزند، آنها را بازخوانی می*کند.
نمونه برنامه ما شاخص*های فایل را بـــا بــکـــارگیــری fdopen، به جـریان*های * FILE تبدیل می*کند (واژه جریان ، معادل stream است).
از آنجا کـــه به جای شاخص*های فایل از جریان ها استفاده می*کنیم، امکان استفاده از توابع ورودی-خروجی سطح بالاتر کتابخانه استاندارد زبان C، مانند printf و fgets وجود دارد.
نمونه برنامه ۱: کاربرد pipe برای ارتباط با پروسه فرزند

کد:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> /* Write COUNT copies of MESSAGE to STREAM, pausing for a second
between each. */ void writer (const char* message, int count, FILE* stream)
{
for (; count > 0; --count) {
/* Write the message to the stream, and send it off immediately. */
fprintf (stream, “%s\n”, message);
fflush (stream); /* Snooze a while. */
sleep (1);
}
}
/* Read random strings from the stream as long as possible. */
void reader (FILE* stream)
{
char buffer[1024]; /* Read until we hit the end of the stream. fgets reads until
either a newline or the end-of-file. */ while (!feof (stream) && !ferror (stream) && fgets (buffer, sizeof (buffer), stream) != NULL){
fputs (buffer, stdout);
} int main ()
{ int fds[2];
pid_t pid; /* Create a pipe. File descriptors for the two ends of the pipe are
placed in fds. */ pipe (fds); /* Fork a child process. */ pid = fork ();
if (pid == (pid_t) 0) {
FILE* stream; /* This is the child process. Close our copy of the write end of
the file descriptor. */
close (fds[1]); /* Convert the read file descriptor to a FILE object, and read
from it. */ stream = fdopen (fds[0], “r”);
reader (stream);
close (fds[0]);
} else { /* This is the parent process. */
FILE* stream; /* Close our copy of the read end of the file descriptor. */ close (fds[0]); /* Convert the write file descriptor to a FILE object, and write
to it. */ stream = fdopen (fds[1], “w”);
writer (“Hello, world.”, 5, stream);
close (fds[1]);
}
return 0;
} در ابتدای تابع main، آرایه*ای از اعداد صحیح به نام fds و با اندازه ۲، اعلان شده است. فــراخوانی تابع pipe پس از ایجاد pipe ، شاخص های فایل خواندنی و نوشتنی را در آن آرایه ذخیره می*کند.
برنامه*ما در ادامه یک پروسه فرزند ایجاد می*کند. پس از بستن سر خواندنی pipe، پروسه ی پدر شروع به نوشتن رشته ها به درون pipe کرده و پس از بستن سر نوشتنی pipe، پروسه فرزند رشته ها را از pipe می*خواند.
منظور از بستن سر pipe، تعیین مرز برای فضایی از حافظه است که به عنوان pipe باید مورد استفاده قرار گیرد.توجه کنید که پروسه*ی پــدر در تابع writer پس از نوشتن در pipe، تابع fflush را فـــراخــوانی و بدین وسیله pipe را وادار می*کند تا رشته را بدون درنگ ارسال نماید.
هنگامی کــه فرمان ls | less را اجرا می*کنید، دو fork انجـــام می*شود؛ یــکــی بــرای پـــروسه ی فرزند ls و دیگری برای پروسه*ی فرزند less. هر دوی این فرزندان شاخص های فایل pipe را به ارث می*برند طوری که بتوانند از طریق pipe ارتباط برقرار کنند. برای برقراری ارتباط بین پروسه های نا مرتبط از FIFO باید استفاده کرد که در ادامه بدان پرداخته خواهد شد
+ نوشته شده توسط امیرحسین عربی زاده در جمعه یازدهم خرداد 1386 و ساعت 16:13 |
بزرگترین سایت جاوا اسکریپت ایران

بهترین و زیباترین کدهای جاوا اسکریپت به همراه آزمایش آن کد