فصل ۱۰ – فرایندها


مقدمه

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

در این فصل می‌آموزیم:


فرایند چیست؟

در اصطلاح سیستم‌عامل، برنامه تنها یک مجموعهٔ ایستا از دستورالعمل‌ها و داده‌ها روی دیسک است؛
اما هنگامی که این برنامه بارگذاری و اجرا می‌شود، هستهٔ سیستم‌عامل نمونه‌ای پویا به نام فرایند می‌سازد.
هر فرایند اطلاعاتی از جمله شناسهٔ یکتا (PID)، فضای آدرس حافظه، دستهٔ فایل‌های باز، متغیرهای محیطی و وضعیت اجرایی خود را نگه می‌دارد.

هر بار که یک برنامه را دوباره اجرا می‌کنیم، حتی اگر از همان فایل باشد، فرایند تازه‌ای ایجاد می‌شود.
فرایندها می‌توانند فرزندهایی بسازند؛ به عنوان مثال، پوسته وقتی دستور جدیدی اجرا می‌کند، یک فرزند می‌سازد که برنامهٔ درخواستی را اجرا کند.
پوستهٔ اصلی به عنوان «فرایند والد» شناخته می‌شود و می‌تواند وضعیت فرزند را پیگیری کند یا منتظر پایان آن بماند.

نشست‌ها، پایانه‌ها و فرایندهای نگهبان

هر بار که وارد پوسته می‌شویم (مثلاً با باز کردن یک پنجرهٔ ترمینال یا ورود از طریق SSH)، فرایندی به نام پوسته با پایانه‌ای تعاملی گره می‌خورد.
فرایندهایی که از این پوسته زاده می‌شوند در یک نشست (session) مشترک قرار می‌گیرند.

برخی فرایندها مانند سرویس‌های سیستمی و «داِمون»‌ها (daemon) پایانه‌ای متصل ندارند و در پس‌زمینهٔ سیستم همیشه فعال‌اند.
در رأس این درخت، معمولاً فرایندی با PID شمارهٔ 1 قرار دارد که در توزیع‌های نوین اغلب همان systemd است.
این فرایند به محض راه‌اندازی هسته آغاز می‌شود و والد بسیاری از داِمون‌ها و نشست‌های کاربری به شمار می‌رود.


مشاهدهٔ فرایندها با ps

یکی از ساده‌ترین راه‌ها برای مشاهدهٔ فهرست فرایندهای فعال، دستور کلاسیک ps است.
این دستور بسته به گزینه‌هایی که به آن می‌دهیم، نمایش‌های مختلفی ارائه می‌دهد.

بدون گزینه، ps معمولاً فقط فرایندهای متصل به پایانهٔ جاری را نشان می‌دهد:

ps

خروجی نمونه:

  PID TTY          TIME CMD
 4342 pts/0    00:00:00 bash
 5021 pts/0    00:00:00 ps

برای دیدن تمام فرایندهای مرتبط با نشست فعلی (حتی آن‌هایی که پایانه ندارند)، از گزینهٔ x استفاده کنید:

ps x

اگر می‌خواهیم تمام فرایندهای سیستم را همراه با مالک آن‌ها ببینیم، گزینه‌های a و u را اضافه می‌کنیم:

ps aux

این نگارش ستون‌هایی مانند مالک فرایند، درصد استفاده از CPU و حافظه، زمان شروع، وضعیت (STAT) و فرمان کامل را نشان می‌دهد.

مرتب‌سازی و فیلتر کردن خروجی

می‌توان خروجی ps را با ابزارهای متنی دیگر ترکیب کرد. برای نمونه، فیلتر کردن فرایندهایی که نام آن‌ها شامل "ssh" است:

ps aux | grep ssh

یا مرتب‌سازی بر اساس مصرف CPU با استفاده از sort:

ps aux --sort=-%cpu | head

گزینهٔ --sort معیارهای متعددی مانند %mem (مصرف حافظه)، pid (شناسهٔ فرایند) یا start_time را می‌پذیرد.

نمایش درختی با pstree

برای درک بهتر رابطهٔ والد و فرزند، می‌توان از pstree بهره برد که ساختار سلسله‌مراتبی فرایندها را نشان می‌دهد:

pstree -p

گزینهٔ -p شناسهٔ فرایندها را کنار نام آن‌ها می‌گذارد. برخی توزیع‌ها ممکن است لازم باشد بستهٔ pstree را به طور جداگانه نصب کنید.


پایش زنده با top

دستور top نمایی پویا از فرایندهای در حال اجرا ارائه می‌دهد و هر چند ثانیه بروزرسانی می‌شود. پس از اجرا، فهرستی از فرایندها به همراه اطلاعاتی دربارهٔ بار CPU، مصرف حافظه، زمان اجرا و وضعیت نمایش داده می‌شود.

top

کلیدهای میانبر درون top:

ابزارهای جایگزین مانند htop رابط کاربرپسندتری دارند، اما top تقریباً روی همهٔ سیستم‌های یونیکسی در دسترس است.


کار با فرایندهای پیش‌زمینه و پس‌زمینه

پوسته به طور معمول هر فرمان را در پیش‌زمینه اجرا می‌کند؛ یعنی کنترل پایانه را تا پایان کار در اختیار دارد. اگر برنامه‌ای زمان‌بر اجرا کنیم، می‌توانیم با افزودن & آن را در پس‌زمینه بفرستیم تا پوسته بلافاصله به ما بازگردد.

long_command &

پوسته PID فرایند پس‌زمینه را گزارش می‌کند و نشان می‌دهد که «کار» (job) جدیدی ایجاد شده است.

تعلیق موقت و ادامهٔ اجرا

اگر فرمانی را بدون & آغاز کرده‌ایم، می‌توانیم با فشردن ترکیب کلید Ctrl+Z آن را موقتاً متوقف (suspend) کنیم. سپس با bg همان فرمان در پس‌زمینه ادامه می‌یابد:

bg %1

در این مثال %1 شمارهٔ کار است. برای بازگرداندن کار به پیش‌زمینه از fg استفاده می‌کنیم:

fg %1

زمانی که فقط یک کار متوقف یا در پس‌زمینه داریم، می‌توان شمارهٔ کار را حذف کرد.

مشاهدهٔ فهرست کارها با jobs

jobs

خروجی نمونه:

[1]+  Stopped                 nano notes.txt
[2]-  Running                 ./backup.sh &

علامت + نشان‌دهندهٔ کاری است که fg یا bg در صورت عدم تعیین شماره انتخاب خواهند کرد؛ علامت - کار بعدی در اولویت است.

خروج از پوسته هنگام وجود کارها

اگر هنگام خروج (exit یا Ctrl+D) هنوز کارهای فعال داشته باشید، پوسته هشدار می‌دهد و مانع خروج می‌شود. برای پایان دادن به همهٔ کارها، آن‌ها را به پیش‌زمینه برگردانید و با Ctrl+C خاتمه دهید یا از kill استفاده کنید.


سیگنال‌ها و پایان دادن به فرایندها

سیگنال‌ها پیام‌هایی هستند که هستهٔ سیستم‌عامل برای اطلاع‌رسانی یا درخواست اقدام به فرایند ارسال می‌کند. برخی سیگنال‌ها قابل نادیده‌گرفتن‌اند، برخی دیگر (مانند SIGKILL) همیشه باعث پایان فرایند می‌شوند.

رایج‌ترین سیگنال‌ها:

سیگنال نام نمادین توضیح
1 SIGHUP پایان نشست یا «آویزان شدن» پایانه؛ بسیاری از داِمون‌ها پس از دریافت آن تنظیمات را دوباره بارگذاری می‌کنند.
2 SIGINT اختلال (Interrupt)؛ همان سیگنالی است که با Ctrl+C ارسال می‌شود و معمولاً باعث خاتمهٔ برنامه می‌شود.
3 SIGQUIT پایان همراه با core dump؛ معمولاً با Ctrl+\ فرستاده می‌شود تا برنامه برای عیب‌یابی ردپا بگذارد.
9 SIGKILL پایان فوری بدون امکان ذخیرهٔ وضعیت؛ فرایند نمی‌تواند آن را مهار یا نادیده بگیرد.
15 SIGTERM درخواست خاتمهٔ نرم؛ فرایند می‌تواند قبل از خروج منابع را آزاد کند.
18/19 SIGCONT ادامهٔ اجرای فرایند متوقف‌شده.
20/17 SIGSTOP توقف اجباری فرایند (مانند Ctrl+Z ولی غیرقابل‌نادیده‌گرفتن).

توجه: شمارهٔ برخی سیگنال‌ها بسته به معماری کمی تفاوت دارد؛ برای مشاهدهٔ فهرست کامل از kill -l استفاده کنید.

استفاده از kill

برای ارسال سیگنال به فرایندی با PID مشخص از kill استفاده می‌کنیم. اگر سیگنالی تعیین نکنیم، پیش‌فرض SIGTERM است.

kill 5021            # ارسال SIGTERM
kill -SIGKILL 5021   # پایان اجباری
kill -9 5021         # معادل بالا با شمارهٔ سیگنال

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

killall و pkill

وقتی PID دقیق را نمی‌دانیم اما نام فرمان مشخص است، killall یا pkill می‌توانند کمک کنند:

killall firefox
pkill -u ali ssh

نمونهٔ دوم تمام فرایندهای ssh متعلق به کاربر ali را خاتمه می‌دهد.

پایان دادن به کارهای پوسته

می‌توان شمارهٔ کار را به kill داد تا سیگنال به فرایند پس‌زمینه ارسال شود:

kill %1

این روش مخصوصاً وقتی چندین نمونه از یک برنامه اجرا شده‌اند و تنها می‌خواهیم یکی از آن‌ها را متوقف کنیم مفید است.


اجرای طولانی و کار در پس‌زمینهٔ پایدار

گاهی لازم است فرمانی حتی پس از خروج از پوسته ادامه یابد. برای این منظور می‌توان از ابزارهایی مانند nohup یا مدیریت‌کننده‌های جلسات (مانند screen و tmux) استفاده کرد.

nohup long_task.sh &

دستور nohup سیگنال SIGHUP را نادیده می‌گیرد و خروجی را در فایل nohup.out ذخیره می‌کند تا کار پس از بستن پایانه نیز ادامه یابد.

ابزارهای screen و tmux محیطی مجازی ایجاد می‌کنند که می‌توان آن را جدا (detach) و دوباره متصل کرد، بدون آن‌که فرایندهای درون‌شان متوقف شوند.


تمیز کردن فرایندهای سرکش

در مواقعی که برنامه‌ای دچار «فرار حافظه» یا حلقهٔ بی‌پایان می‌شود، می‌توانیم با top یا ps فرایند را شناسایی و سپس سیگنال مناسب ارسال کنیم. گام‌های پیشنهادی:

  1. با top یا ps aux --sort=-%cpu فرایند مشکل‌ساز را بیابید.
  2. ابتدا kill PID (سیگنال پیش‌فرض) را امتحان کنید.
  3. اگر پاسخ نگرفتید، پس از چند ثانیه دوباره با kill -SIGTERM PID تلاش کنید.
  4. در صورت لزوم نهایتاً kill -SIGKILL PID را اجرا کنید.

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


جمع‌بندی

در فصل‌های بعدی با محیط اجرا و متغیرهای پوسته آشنا می‌شویم تا بتوانیم رفتار فرایندها را دقیق‌تر شخصی‌سازی کنیم.