| کنترل پروسسها با استفاده از سیگنالها در لینوکس |
|
|
| مقالات - مقالات | ||||||||
| نویسنده خانم شکیباپور | ||||||||
| ۰۱ خرداد ۱۳۸۷ | ||||||||
کنترل پروسسها با استفاده از سیگنالهادر این مقاله در مورد کنترل پروسسها بحث می کنیم:سیگنالهایی که به پروسسها فرستاده می شوند، چگونگی رفتار پوسته (shell) با پروسسها و همچنین جزئیاتی در مورد کنترل job ها. معرفی سیگنالهااز روزهای اولیه ظهور لینوکس ، کاربران پروسسهای خود را با فرستادن سیگنالی با دستور kill خاتمه می داده اند.بعضی از این سیگنالها یک پروسس را kill نمی کنند:آنها به پروسس اعلام می کنند (که فایل تنظیمات خودش را دوباره بخواند) ، پروسس را به تعویق می اندازند ، یا اینکه آن را دوباره راه اندازی می کنند.آرگومان اول دستور kill ، سیگنالی است که می خواهید بفرستید ؛ آرگومانهای دیگر شماره job (ها) یا PID پروسس (ها) یی است که باید سیگنال را دریافت کنند.شما همچنین می توانید یک سیگنال را به یک پروسس foreground با زدن کلید های ترکیبی CRTL-C یا CTRL-Z روی صفحه کلیدتان بفرستید. توجه کنید که معمولا شما تنها می توانید سیگنالها را به پروسسهای خودتان بفرستید.تنها کاربر root است که مجاز به ارسال سیگنال به هر پروسس در حال اجرا روی سیستم است. هر سیگنال هم دارای یک مقدارعددی و هم یک نام است.بعضی از سیگنالها دارای یک مقدار و نام واحد روی تقریبا هر سیستمی هستند.به عنوان مثال ، سیگنال 15، با نام SIGTERM،سیگنال پیش فرضی است که توسط kill فرستاده می شود.سیگنال 2،SIGINT،سیگنال "وقفه از صفحه کلید" است که با فشردن کلیدهای CTRL-C فرستاده می شود.(برای تغییر سیگنالهای پیش فرض فرستاده شده توسط ترکیبات مختلف کلیدها در طول session ورودی خود، از stty استفاده کنید.) لیست سیگنالها در نسخه های مختلف لینوکس و یونیکس تفاوت می کند و بعضی سیگنالها مخصوص سیستمهای خاصی هستند.صفحه man برای signal و فایل سرآیند (signal.h) را برای شناختن سیگنالهای سیستم خودتان مشاهده کنید. بعضی از سیگنالها ، می توانند توسط یک پروسس گرفته شوند؛ این همچنین می تواند از تأثیر پیش فرض سیگنال جلوگیری کند یا اینکه آن را به تأخیر بیندازد.به عنوان مثال، یک پروسس می تواند SIGTERM را بگیرد و پاکسازی (clean up) شود یعنی فایلهای موقتی خود را قبل از پایان دادن به خود ، حذف کند.به عنوان مثال دیگر، SIGINT به هیچ وجه vim را خاتمه نمی دهد؛ در عوض ویرایشگر از insert mode خارج شده و هر دستور در حال انجامی را لغو می کند.SIGHUP، سیگنال 1، از هنگامی آغاز شد که مردم از خطوط dialup برای اتصال به سیستمها استفاده کردند.SIGHUP به هر پروسس باقیمانده کاربر پس از قطع شدن (تلفن را قطع کردن) فرستاده می شد.اگر شما می خواستید یک پروسس حتی پس از خروج شما به اجرای خود ادامه دهد، باید پروسس را با استفاده از nohup آغاز می کردید، که SIGHUP را گرفته ولی آن را نادیده می انگارد بنابراین پروسس های فرزندش با خروج خاتمه نمی یابد. بعضی از سیگنالها،مانندSIGQUIT (که با \-CTRL فرستاده می شود) ،که باعث یک رونوشت حافظه (core dump) قبل از خاتمه یک پروسس می گردد.از این سیگنالها استفاده نکنید مگر اینکه بخواهید یک پروسس را debug کنید. یک سری از سیگنالهای مشخص نمی توانند گرفته (catch) شوند؛آنها بی درنگ تأثیر خود را می گذارند.بهترین مثال _سیگنال 9،SIGKILL_ است که تقریبا هر پروسسی را خاتمه می دهد.یک پروسس نمی تواند بعد از SIGKILL پاکسازی (clean up) شود، بنابراین شما معمولاً از آن استفاده نخواهید کرد مگر اینکه ابتدا از سیگنالهایی که کمتر سخت گیر هستند استفاده کنید.ُُبرای مثال،برای متوقف کردن یک پروسس، ابتدا SIGTERM را امتحان کنید و قبل از تسلیم شدن و فرستادن SIGKILL چند ثانیه ای صبر کنید. حتی یک سیگنال غیر قابل گرفتن (uncatchable) هم ممکن است نتواند به یک پروسس خاتمه دهد.برای مثال یک zombie باقیمانده یک پروسس است که منتظر خروج (exit) است.(یک zombie در ستون STَََAT دستور ps با Z نمایش داده می شود.) یک پروسس که در حال ردگیری (trace) است نیز می تواند غیرقابل کشتن (unkillable) باشد. در آخر، یک گروه از سیگنالها هستند که وظیفه معلق (suspend) کردن و بازسرگیری (resume) پروسسها را بر عهده دارند.پس از معرفی کنترل job ها به آنها می پردازیم. سیر تکاملی کنترل jobسیستمهای اولیه یونیکس کنترل پروسس نسبتاً ساده ای داشتند:برای فرستادن سیگنال به یک پروسس، کاربر PID آن را پیدا می کرد و از kill استفاده می کرد.هنگام اجرا کردن برنامه ها از اعلان پوسته (shell prompt) ،شما می توانستید آن را در foreground با تایپ در خط فرمان اجرا کنید و منتظر به پایان رسیدن آن باشید یا اینکه آن را در background با گذاشتن علامت & بعد از نام دستور و آرگومانهایش اجرا کنید. در آن روزها، شما تنها یک terminal داشتید.هنگامی که یک پروسس آغاز می شد در foreground ، تنها انتخاب شما برای گرفتن یک اعلان پوسته (shell prompt) جدید در terminal تان این بود که منتظر به پایان رسیدن آن باشید یا اینکه آن را با یک سیگنال خاتمه می دادید.اگر شما می دانستید که آن برنامه احتمالاً زمان اجرایش طولانی خواهد بود،باید از قبل فکرش را می کردید و آن را در background اجرا می کردید بنابراین می توانستید اعلان پوسته (shell prompt) دیگری را بگیرید و در حالی که آن پروسس در background در حال اجرا بود، کارهای دیگری را در foreground انجام بدهید. بنابراین این ساختار بسیار از batch processing (ارسال بسته ای از کارتها برای اجرا طبق ترتیبی که اپراتور سیستم مشخص می کند) بهتر بود.عاقبت سیستمهای پنجره ای آمدند و به کاربران اجازه اجرای هر تعداد دستور foregroundی که می خواستند ،هر کدام در یک پنجره، را می دادند.در این بین کنترل job توسعه یافت برای اینکه به کاربران کنترل بیشتری روی پروسسهایشان بدهد. کنترل job تغییراتی را در هسته و پوسته ایجاد کرده است.(در ابتدا تنها برای پوسته C موجود بوده است.) شما می توانید یک سیگنال را به یک گروه از پردازشها ،که مجموعه ای از یک یا تعداد بیشتری پروسس است، بفرستید.همچنین یک مجموعه جدیدی از سیگنالها _SIGSTOP,SIGTSTP وSIGCONT_ با عنوان پروسسهای فردی یا گروههای پروسس برای به تعویق انداختن و بازسرگیری به کار می رود. Job واژه ای است برای تعریف یک یا چند پردازش که تحت یک پروسس پوسته در حال اجرا هستند، استفاده می شود.حداکثر یک job foreground می تواند وجود داشته باشد؛ پوسته قبل از اینکه اعلان(prompt) دیگری را بدهد ، منتظراتمام پروسس یا پروسسهای یک job می ماند.برای مثال اگر شما تایپ کنید cp * /somedir، پوسته متنظر می ماند تا cp کپی کردنش را تمام کند تا prompt جدید را نمایش دهد یا اینکه شما می توانید با یک سیگنال (برای مثال CTRL-C) cp را kill کنید. کنترل job انتخاب دیگری به شما می دهد:به تعویق انداختن job foreground با تایپ CTRL-Z.با این کار سیگنال SIGTSTP ،"terminal stop"، که می تواند توسط یک پروسس گرفته شود ، فرستاده می شود.این کار به یک ویرایشگر متنی این امکان را می دهد تا قبل از اینکه پروسس به تعویق بیفتد ،صفحه شما را به یک شرایط قابل قبولی restore کند.وقتی شما یک job foreground را متوقف کرده اید،می توانید job را با کنترل job با استفاده از شماره آن job اداره کنید.اولین job متوقف شده یا background ، job number 1 را دارد (نوشته می شود %1 ) ، دومی job 2 است و به همین ترتیب.برای فرستادن سیگنال "از سرگیری"، SIGCONT، به پروسس (های) داخل یک job، تایپ کنید fg%1 برای از سرگیری job در foreground (پوسته منتظر آن می ماند) یا bg%1 برای اجرا در background.اگر شما تنها یک job در حال اجرا داشته باشید، job number ضروری نیست، بنابراین اگر تنها یک job متوقف موجود باشد، fg شما را به پروسس به تعویق انداخته شده باز می گرداند. سیگنال به تعویق انداختن دیگر،SIGSTOP، نمی تواند گرفته شود یا به کار برده شود.همچنانکه در قسمت بعدی می بینیم، این یک انتخاب خوب برای پروسس های background و daemon است. شما می توانید سیگنالهای دیگری را نیز با kill بفرستید.برای مثال، kill %1 سیگنال SIGTERM را به job شماره 1 می فرستد.از kill -9 %2,kill –sigkill %2 یا kill –kill %2 برای فرستادن SIGKILL به job شماره 2 استفاده کنید. ما کنترل job را عمقی بررسی نخواهیم کرد؛ برای اینکارصفحه manual پوسته خود یا هر مرجع لینوکسی دیگر را ببینید.نکته مهم این است که کنترل job به شما امکان متوقف کردن پروسس ها به صورت یک گروه،از سرگیری آنها در foreground یا background، یا خاتمه دادن آنها با استفاده از یک job number را می دهد.
به یاد آوری پروسسهای به تعویق انداخته شدهشما می توانید راجع به پروسس به صورت مجموعه ای از مشخصه ها که تا پایان پروسس نگهداری می شوند ، نگاه کنید.از جمله این مشخصه ها دایرکتوری جاری،لیستی از متغیرهای محیطی و فایلهای باز هستند. هسته لینوکس تنها موقعی یک پروسس را اجرا می کند که منابعی مانند دیسک و شبکه آماده باشند_و در طول زمان slice CPU اش.در زمانهای دیگر یک پروسس منتظر می شود یا به تعویق می افتد. اگر یک پروسس به تعویق بیفتد_یا توسط هسته لینوکس یا توسط شما با استفاده از صفحه کلید_ پروسس مشخصه هایش را نگهداری می کند.وقتی یک پروسس از سر گرفته می شود، از همان جایی که ترک شده آغاز می شود.برای مثال،همان دایرکتوری جاری را دارد.از همان نقاط در همان فایلها می خواند و می نویسد.برای نمونه، این یک دلیل برای معوق کردن یک ویرایشگر متنی به جای خارج شدن و دوباره آغاز کردن آن است. به سادگی تایپ کنید CTRL-Z برای یک job foreground ،یا kill –stop %n برای متوقف کردن یک job background .(پوسته های C و tcsh دستور built-in stop را دارند.اگر از پوسته دیگری استفاده می کنید، یک alias برای kill –stop بسازید.) بعضی مواقع شما می خواهید SIGSTOP را برای پروسسی بفرستید که در background session پوسته شما در حال اجرا نیست.برای نمونه، اگر شما یک مدیر سیستم با یک سیستم شلوغ باشید؛ شما ممکن است یک پروسسی که مدت طولانی است که در حال اجراست، یا پروسسی که حساس به CPU است، یا پروسسی که به نظر فراری می رسد را با استفاده از kill –STOP به تعویق بیندازید.سپس منتظر شوید تا load سیستم پایین بیاید یا اینکه دنبال مدارکی دال بر مشکل داشتن آن پروسس بگردید (با خواندن فایلهای موقتی، صحبت با کاربری که آن پروسس را اجرا کرده است و ...).از kill –CONT برای دوباره اجرا کردن آن پروسس استفاده کنید. گرفتن سیگنالها از پوستهانواع پوسته های Bourne مانند GNU Bash ،signal handling انعطاف پذیری دارند.دستور built-in trap این کار را انجام می دهد. signal handlingدر tcsh بسیار محدود تر است.zsh طبق معمول signal handling بسیار پیچیده تری دارد.شما نوعاً نمی خواهید trap را در یک پوسته login اعمال کنید( پوسته ای که شما به صورت تعاملی از طریق prompt پوسته با آن کار می کنید).به طور عمومی trap را از shell script صدا می زنید.ساختار trap به صورت زیر است: trap todo signal(s) آرگومان (signal(s ، یک یا بیشتر شماره سیگنال است (2 برای SIGINT، 15 برای SIGKILL، و به همین ترتیب) که trap آن را استفاده می کند.بیشتر پوسته ها نام سیگنالها را نیز می پذیرند.todo عملی است که به هنگام دریافت سیگنالها صورت می پذیرد، و احتمالات گوناگونی وجود دارد:
یک استفاده معمول از trap پاکسازی فایلهای موقتی قبل از خروج است.اسکریپت زیر نمونه اسکریپتی است که این کار را انجام می دهد.
Traptest shell script #!/bin/sh tmp=/tmp/afile # dummy file stat=1 # exit status echo temp file for $0 > $tmp trap ‘echo ouch!; rm –f $tmp; exit’ 2 15 trap ‘echo bye; exit $stat’ 0 echo “sleep #1…” 1>&2 sleep 5 stat=0 echo “sleep #2…” 1>&2 sleep 5
اسکریپت با ایچاد یک فایل موقتی که حاوی یک خط متن است آغاز می شود.سپس وضعیت خروجی (exit status) اسکریپت را در متغیر پوسته stat$ ذخیره می کند؛این مقدار به دستورexit که داخل trap دومی است پاس می شود.در اواخر اسکریپت، stat$ صفر می شود تا موفقیت را نشان بدهد. این اسکریپت 2 trap دارد:
توجه کنید که دستورات برای هر دو trap ها داخل یک جفت single quote قرار می گیرد. Single quoteها از مقدارگیری هر متغیر پوسته که داخل quote ها قرار دارند جلوگیری می کنند، بنابراین tmp$ وstat$ به شکل حروف اصلی بسط می یابند.مقادیر متغیرهای پوسته درزمان فعال شدن trap بسط می یابند.این بسیار مهم است چون می خواهیم مقدارstat$ درست در لحظه shell exit یا همان سیگنال 0، ویرایش شود، نه در موقعی که trap تنظیم می شود.در حقیقت پوسته متن todo را دو مرتبه پویش می کند.دفعه اول هنگامی است که آماده اجرای می شود؛ همه جایگزینی ها قبل از اجرای دستورtrap انجام می شود.دفعه دوم هنگامی است که پوسته واقعاً trap را اجرا می کند. (قرار دادن دستورات داخل double quote ،””، باعث بسط stat$ و tmp$ درهنگام تنظیم شدن trap می شود.) بعد از اینکه trap ها تنظیم شدند، اسکریپت “sleep# 1″ را echo می کند و 5 ثانیه مکث می کند.سپس stat$ را صفر می کند،“sleep# 2″ را echo می کند، و 5 ثانیه دیگر مکث می کند.این مکث ها به شما امکان ارسال سیگنال را به اسکریپت می دهد. بیایید اسکریپت را به سه روش مختلف امتحان کنیم.اول، CTRL-C را حین اولین trap تایپ می کنیم تا اولین trap فعال شود. از “ouch!” و“bye” می توان فهمید که هر دو trap فعال شده اند.اسکریپت با وضعیت 1 خارج می شود همچنانکه دستور ?$ echo نشان می دهد (چون پارامتر?$ حاوی وضعیت خروجی دستور قبلی است ): $ ./traptest sleep #1… ^C ouch! Bye $ echo $? 1
سپس، سیگنال 2 را حین sleep دومی ارسال می کنیم.وضعیت خروجی اسکریپت صفر خواهد بود چون stat$ با مقدار0 تنظیم شده بوده است:
$ ./traptest sleep #1… sleep #2… ^C ouch! Bye $ echo $? 0
در پایان، اگر بگذاریم اسکریپت به طور کامل اجرا شود، تنها trap دوم فعال خواهد شد:
$ ./traptest sleep #1… sleep #2… bye $ echo $? 0 نویسنده: Jerry Peek بازدید: 1036
|
||||||||
| آخرین بروز رسانی ( ۱۸ خرداد ۱۳۸۷ ) | ||||||||
| <قبل | بعد> |
|---|
| صفحه اصلی |
| اخبار |
| مقالات |
| جستجوی پیشرفته |
| یزدلاگ در رسانه |
| تازه کاران |
| مدیریت |