کتابخانه‌ی استاندارد · سیستم و ابزار

فرآیند os/process

اجرای برنامه‌های دیگر، گرفتن خروجی‌شان، صبر برای پایانشان و متوقف کردنشان.

واردسازی سیستم عامل.فرآیند

بسته‌ی فرآیند یک برنامه‌ی دیگر را مستقیم، بدون پوسته، اجرا می‌کند. مسیر برنامه و آرگومان‌ها جدا داده می‌شوند، پس نیازی به نقل‌قول‌گذاری نیست و فاصله‌ها یا نویسه‌های خاص در آرگومان‌ها مشکلی درست نمی‌کنند. با آن ابزارهایی مثل git، ffmpeg یا یک کامپایلر را با نام پرونده‌هایی که از کاربر آمده صدا بزنید. برای یک فرمان یک‌خطی پوسته بسته‌ی سیستم عامل (اجرا، اجرا با خروجی) یا پوسته را ببینید؛ وقتی برنامه‌ای اصلاً اجرا نمی‌شود، دلیلش در خطا ثبت می‌شود.

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

اشتباه‌های رایج:

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

در ویندوز آرگومان‌ها به یک خط فرمان پیوسته می‌شوند و فقط آن‌هایی که فاصله دارند در نقل‌قول می‌روند، و برنامه با CreateProcessA (نسخه‌ی ANSI) اجرا می‌شود. آرگومانی که خودش " دارد، یا متنی بیرون از صفحه‌کد سیستم مثل فارسی، آن‌جا سالم نمی‌رسد؛ انشعاب و انتظار شناسه هم -۱ برمی‌گردانند.

رساندن آرگومان‌ها همان‌طور که هستند

هر عضو وکتور آرگومان‌ها، بایت به بایت، یک آرگومان برای برنامه می‌شود. فاصله، نقل‌قول، $ یا ; معنای خاصی ندارند، چون هیچ پوسته‌ای آن‌ها را نمی‌خواند. برای همین این بسته راه امن رساندن نام پرونده‌ها و هر متنی است که از کاربر آمده.

os-process-guide-args.salam
واردسازی سیستم عامل.فرآیند

تابع ریشه:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("[%s]\n")
    آرگ.بیفزا("دو واژه")
    آرگ.بیفزا("it's quoted")
    آرگ.بیفزا("$HOME")
    آرگ.بیفزا("*.txt; rm -rf x")
    ناپایا ف := فرآیند.شروع با ضبط("printf"، آرگ)
    فرآیند.انتظار(ف)
    چاپ فرآیند.خواندن خروجی(ف)
    فرآیند.پاکسازی(ف)
پایان
خروجی[دو واژه] [it's quoted] [$HOME] [*.txt; rm -rf x]

نام برنامه مثل پایانه در PATH جستجو می‌شود، پس printf بدون مسیر کامل هم کار می‌کند. خود نام برنامه در وکتور نمی‌آید؛ بسته آن را می‌افزاید. این دقت در لینوکس و مک برقرار است؛ برای ویندوز یادداشت بالا را ببینید.

کد خروج، خروجی و خروجی خطا

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

os-process-guide-exitcode.salam
واردسازی سیستم عامل.فرآیند

تابع ریشه:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("-c")
    آرگ.بیفزا("echo در حال رونوشت; echo دیسک پر است >&2; exit 3")
    ناپایا ف := فرآیند.شروع با ضبط("sh"، آرگ)
    کد := فرآیند.انتظار(ف)
    خروجی := فرآیند.خواندن خروجی(ف).پیراست()
    پیام خطا := فرآیند.خواندن خطا(ف).پیراست()
    فرآیند.پاکسازی(ف)
    سرچاپ "خروجی:"، خروجی
    اگر کد != ۰:
        سرچاپ "با کد"، کد، "شکست خورد و گفت:"، پیام خطا
        برگشت ۰
    پایان
    سرچاپ "همه چیز درست بود"
پایان
خروجیخروجی: در حال رونوشت با کد 3 شکست خورد و گفت: دیسک پر است

اجرای چند برنامه با هم

شروع با ضبط همین که برنامه راه افتاد برمی‌گردد، پس می‌توانید چند برنامه را شروع کنید و بعد برای همه صبر کنید. زمان کل نزدیک به زمان کندترینشان است، نه جمع همه. اگر به همان ترتیبی که شروع کرده‌اید صبر کنید، ترتیب خروجی ثابت می‌ماند، حتی اگر کاری که دیرتر شروع شده زودتر تمام شود.

os-process-guide-parallel.salam
واردسازی سیستم عامل.فرآیند

تابع کار(نام: رشته، ثانیه: رشته): فرآیند.فرآیند:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("-c")
    آرگ.بیفزا("sleep " + ثانیه + "; echo " + نام + " تمام شد")
    برگشت فرآیند.شروع با ضبط("sh"، آرگ)
پایان

تابع ریشه:
    ناپایا کارها := وکتور {} برگردان وکتور<فرآیند.فرآیند>
    دیرکن کارها.آزادکن()
    کارها.بیفزا(کار("تصویرک‌ها"، "0.3"))
    کارها.بیفزا(کار("نمایه‌ی جستجو"، "0.1"))
    کارها.بیفزا(کار("نقشه‌ی سایت"، "0.2"))
    سرچاپ کارها.طول()، "کار شروع شد"
    تکرار کارها.طول() در ش:
        ناپایا ف := کارها.بگیر(ش)
        کد := فرآیند.انتظار(ف)
        سرچاپ کد، فرآیند.خواندن خروجی(ف).پیراست()
        فرآیند.پاکسازی(ف)
    پایان
پایان
خروجی3 کار شروع شد 0 تصویرک‌ها تمام شد 0 نمایه‌ی جستجو تمام شد 0 نقشه‌ی سایت تمام شد

تعداد برنامه‌های هم‌زمان را معقول نگه دارید؛ برای کارهایی که پردازنده را درگیر می‌کنند، تعداد پردازنده از بسته‌ی سکو سقف خوبی است.

تابع کمکی‌ای که برنامه را اجرا می‌کند و خروجی را برمی‌گرداند

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

os-process-guide-helper.salam
واردسازی سیستم عامل.خطا
واردسازی سیستم عامل.فرآیند

تابع ضبط(برنامه: رشته، آرگ: وکتور<رشته>، موفق &: منطقی): رشته:
    خطا.پاک کردن خطا()
    ناپایا ف := فرآیند.شروع با ضبط(برنامه، آرگ)
    اگر خطا.خطا دارد():
        موفق = نادرست
        برگشت ""
    پایان
    دیرکن فرآیند.پاکسازی(ف)
    موفق = فرآیند.انتظار(ف) == ۰
    برگشت فرآیند.خواندن خروجی(ف)
پایان

تابع ریشه:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("-c")
    آرگ.بیفزا("printf '۳۰\\n۱۰\\n۲۰\\n' | sort")
    ناپایا موفق := نادرست
    خروجی := ضبط("sh"، آرگ، موفق)
    سرچاپ "موفق بود:"، موفق
    چاپ خروجی
    ضبط("/no/such/tool"، آرگ، موفق)
    سرچاپ "ابزار ناموجود موفق بود:"، موفق
پایان
خروجیموفق بود: true ۱۰ ۲۰ ۳۰ ابزار ناموجود موفق بود: false

متوقف کردن یک برنامه

پایان دادن علامت SIGTERM را می‌فرستد که برنامه‌ی درست‌رفتار آن را می‌گیرد تا کارش را ذخیره کند و بیرون برود؛ کشتن علامت SIGKILL را می‌فرستد که گرفتنی نیست. در هر دو حالت، پس از آن انتظار برنامه را جمع می‌کند. برنامه‌ای که با علامت تمام شده، ۱۲۸ به‌علاوه‌ی شماره‌ی علامت را به‌عنوان کد خروج گزارش می‌کند؛ پس ۱۴۳ یعنی SIGTERM و ۱۳۷ یعنی SIGKILL، همان عددهایی که پوسته نشان می‌دهد.

os-process-guide-stop.salam
واردسازی سیستم عامل.فرآیند

تابع ریشه:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("30")
    ناپایا کارگر := فرآیند.شروع("sleep"، آرگ)
    سرچاپ "شروع شد، در حال اجرا:"، فرآیند.در حال اجرا(کارگر)
    اگر فرآیند.پایان دادن(کارگر) != ۰:
        سرچاپ "نتوانستم به آن علامت بفرستم"
        برگشت ۱
    پایان
    کد := فرآیند.انتظار(کارگر)
    سرچاپ "با کد خروج"، کد، "متوقف شد = 128 + علامت"، کد - ۱۲۸
    سرچاپ "در حال اجرا:"، فرآیند.در حال اجرا(کارگر)
    برگشت ۰
پایان
خروجیشروع شد، در حال اجرا: true با کد خروج 143 متوقف شد = 128 + علامت 15 در حال اجرا: false
نیازچه به کار ببرید
اجرای برنامه و دیدن خروجی‌اش روی صفحهشروع، سپس انتظار
اجرای برنامه و استفاده از خروجی‌اششروع با ضبط، انتظار، خواندن خروجی، پاکسازی
متوقف کردن مؤدبانه یا فوریپایان دادن، کشتن
لوله یا هدایت خروجیاجرای sh با -c و یک اسکریپت، مثل نمونه‌های بالا
یک فرمان یک‌خطی و نتیجه‌اشپوسته

گونه‌ها

فرآیند Process

ساختار فرآیند
یک فرآیند در حال اجرا یا تمام‌شده.
نامانگلیسیگونهتوضیح
شناسهpidصحیح = 0شناسه‌ی فرآیند.
دستهhandleتهی*دستگیره‌ی فرآیند در ویندوز.
فعالrunningمنطقی = نادرستشروع روشنش می‌کند و انتظار، کشتن و پایان دادن خاموشش؛ وقتی برنامه خودش تمام شود به‌روز نمی‌شود.
کد خروجexit_codeصحیح = 0کد خروج، پس از برگشتن انتظار؛ اگر علامتی برنامه را تمام کرده باشد، ۱۲۸ به‌علاوه‌ی شماره‌ی علامت.
مسیر خروجیstdout_pathرشته = ""پرونده‌ی موقتی که خروجی ضبط‌شده در آن است.
مسیر خروجی خطاstderr_pathرشته = ""پرونده‌ی موقتی که خروجی خطای ضبط‌شده در آن است.
os-process-Start.salam
واردسازی سیستم عامل.فرآیند

تابع ریشه:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("سلام از فرآیند فرزند")
    ناپایا ف := فرآیند.شروع با ضبط("/bin/echo"، آرگ)
    سرچاپ فرآیند.شناسه فرآیند(ف) > ۰
    کد := فرآیند.انتظار(ف)
    سرچاپ کد، فرآیند.کد خروج(ف)، فرآیند.در حال اجرا(ف)
    چاپ فرآیند.خواندن خروجی(ف)
    سرچاپ "[" + فرآیند.خواندن خطا(ف) + "]"
    فرآیند.پاکسازی(ف)
پایان
خروجیtrue 0 0 false سلام از فرآیند فرزند []

تابع‌ها

شروع Start

تابع شروع(path: رشته، args: وکتور<رشته>): فرآیند
برنامه را با آرگومان‌ها اجرا می‌کند و منتظر نمی‌ماند؛ خروجی‌اش مستقیم در خروجی برنامه‌ی شما چاپ می‌شود. نام در PATH جستجو می‌شود. اگر اجرا نشود، pid صفر است و خطا مقدار فرآیند ناموفق را نگه می‌دارد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

شروع با ضبط StartCaptured

تابع شروع با ضبط(path: رشته، args: وکتور<رشته>): فرآیند
مثل شروع، ولی خروجی و خطای برنامه را به دو پرونده‌ی موقت می‌فرستد تا پس از انتظار بخوانید، و ورودی استاندارد خالی به آن می‌دهد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

انتظار شناسه WaitPid

تابع انتظار شناسه(pid: صحیح): صحیح
صبر می‌کند تا فرآیندی با این شناسه تمام شود و کد خروجش یا -۱ را برمی‌گرداند. فقط یونیکس؛ در ویندوز -۱ برمی‌گرداند.
os-process-Kill.salam
واردسازی سیستم عامل.فرآیند

تابع ریشه:
    ناپایا آرگ := وکتور {} برگردان وکتور<رشته>
    دیرکن آرگ.آزادکن()
    آرگ.بیفزا("30")
    ناپایا ف := فرآیند.شروع("/bin/sleep"، آرگ)
    سرچاپ فرآیند.در حال اجرا(ف)
    فرآیند.پایان دادن(ف)
    فرآیند.انتظار(ف)
    سرچاپ فرآیند.در حال اجرا(ف)
    ناپایا ف۲ := فرآیند.شروع("/bin/sleep"، آرگ)
    فرآیند.کشتن(ف۲)
    فرآیند.انتظار شناسه(فرآیند.شناسه فرآیند(ف۲))
    سرچاپ "هر دو متوقف شدند"
پایان
خروجیtrue false هر دو متوقف شدند

انتظار Wait

تابع انتظار(p &: فرآیند): صحیح
صبر می‌کند تا فرآیند تمام شود و کد خروجش را برمی‌گرداند: اگر علامتی آن را تمام کرده باشد ۱۲۸ به‌علاوه‌ی شماره‌ی علامت، و اگر هرگز اجرا نشده باشد -۱. مهلت زمانی ندارد.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

انشعاب Fork

تابع انشعاب(): صحیح
فرآیند فعلی را دو تا می‌کند: در فرزند صفر برمی‌گرداند و در والد شناسه‌ی فرزند. فقط روی سیستم‌های یونیکس؛ نمونه‌اش اینجا اجرا نمی‌شود.
os-process-Fork.salam
واردسازی سیستم عامل.فرآیند

تابع ریشه:
    ش := فرآیند.انشعاب()
    اگر ش == ۰:
        سرچاپ "من فرزندم"
        فرآیند.خروج فوری(۰)
    پایان
    فرآیند.انتظار شناسه(ش)
    سرچاپ "فرزند تمام شد"
پایان

خروج فوری ExitNow

تابع خروج فوری(code: صحیح)
فرآیند را فوراً و بدون هیچ پاک‌سازی تمام می‌کند؛ برای پایان دادن به فرزند پس از انشعاب.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Fork.salam

کشتن Kill

تابع کشتن(p &: فرآیند): صحیح
فرآیند را بی‌درنگ می‌کشد (SIGKILL)؛ اگر علامت فرستاده شود ۰. پس از آن انتظار را صدا بزنید تا جمعش کند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Kill.salam

پایان دادن Terminate

تابع پایان دادن(p &: فرآیند): صحیح
از فرآیند می‌خواهد با آرامش تمام کند (SIGTERM) تا فرصت پاکسازی داشته باشد؛ پس از آن انتظار را صدا بزنید. در ویندوز همان کشتن است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Kill.salam

خواندن خروجی ReadStdout

تابع خواندن خروجی(p: فرآیند): رشته
خروجی ضبط‌شده را پس از پایان فرآیند می‌خواند؛ برای فرآیندی که با شروع اجرا شده خالی است. متن در نخستین بایت صفر تمام می‌شود.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

خواندن خطا ReadStderr

تابع خواندن خطا(p: فرآیند): رشته
خروجی خطای ضبط‌شده را می‌خواند؛ برای فرآیندی که با شروع اجرا شده خالی است.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

پاکسازی Cleanup

تابع پاکسازی(p &: فرآیند)
پرونده‌های موقت ضبط را پاک می‌کند. اول خروجی را بخوانید؛ برای هر شروع با ضبط یک بار صدایش بزنید.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

کد خروج ExitCode

تابع کد خروج(p: فرآیند): صحیح
کد خروج فرآیند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

شناسه فرآیند Pid

تابع شناسه فرآیند(p: فرآیند): صحیح
شناسه‌ی فرآیند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam

در حال اجرا IsRunning

تابع در حال اجرا(p: فرآیند): منطقی
پرچم running: از شروع تا انتظار، کشتن یا پایان دادن درست است. از سیستم نمی‌پرسد، پس پس از این‌که برنامه خودش تمام شد هم درست می‌ماند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: os-process-Start.salam