GeezerVison is showing python.github.io — signal --- تنظیم هندلرها برای رویدادهای ناهمگام
signal --- تنظیم هندلرها برای رویدادهای ناهمگام¶
کد منبع: Lib/signal.py
این ماژول سازوکارهایی را برای استفاده از هندلرهای سیگنال در پایتون فراهم میکند.
قواعد عمومی¶
تابع signal.signal() به شما اجازه میدهد هندلرهای سفارشی را تعریف کنید تا هنگام دریافت یک سیگنال اجرا شوند. تعداد اندکی از هندلرهای پیشفرض نصب شدهاند: SIGPIPE نادیده گرفته میشود (تا خطاهای نوشتن روی پایپها و سوکتها بتوانند بهعنوان استثناهای معمول پایتون گزارش شوند) و SIGINT در صورتی که فرایند والد آن را تغییر نداده باشد، به استثنای KeyboardInterrupt تبدیل میشود.
یک هندلر برای یک سیگنال خاص، پس از تنظیم شدن، تا زمانی که بهصراحت بازنشانی نشود، نصبشده باقی میماند (پایتون صرفنظر از پیادهسازی زیربنایی، رابط به سبک BSD را شبیهسازی میکند)، به استثنای هندلر SIGCHLD که از پیادهسازی زیربنایی پیروی میکند.
در پلتفرمهای WebAssembly، سیگنالها شبیهسازی میشوند و بنابراین رفتار متفاوتی دارند. چندین تابع و سیگنال در این پلتفرمها در دسترس نیستند.
اجرای هندلرهای سیگنال پایتون¶
هندلر سیگنال پایتون درون هندلر سیگنال سطح پایین (C) اجرا نمیشود. در عوض، هندلر سیگنال سطح پایین پرچمی را تنظیم میکند که به virtual machine میگوید هندلر سیگنال پایتون متناظر را در نقطهای بعدی (برای مثال، در دستور bytecode بعدی) اجرا کند. این موضوع پیامدهایی دارد:
گرفتن خطاهای همگام مانند SIGFPE یا SIGSEGV که در اثر یک عملیات نامعتبر در کد C ایجاد میشوند، چندان منطقی نیست. پایتون از هندلر سیگنال به کد C بازمیگردد، که احتمال دارد همان سیگنال را دوباره پرتاب کند و باعث شود پایتون ظاهراً هنگ کند. از پایتون 3.3 به بعد، میتوانید از ماژول faulthandler برای گزارش خطاهای همگام استفاده کنید.
محاسبهای طولانیمدت که بهطور کامل در C پیادهسازی شده باشد (مانند تطبیق عبارت باقاعده روی حجم بزرگی از متن) ممکن است صرفنظر از هر سیگنال دریافتی، برای مدت زمانی دلخواه بدون وقفه اجرا شود. هندلرهای سیگنال پایتون هنگامی که محاسبه به پایان برسد فراخوانی خواهند شد.
اگر هندلر استثنایی را پرتاب کند، آن استثنا «بهصورت ناگهانی» در نخ اصلی پرتاب خواهد شد. برای توضیحات بیشتر، یادداشت زیر را ببینید.
سیگنالها و نخها¶
هندلرهای سیگنال پایتون همیشه در نخ اصلی پایتون در مفسر اصلی اجرا میشوند، حتی اگر سیگنال در نخ دیگری دریافت شده باشد. این بدان معناست که نمیتوان از سیگنالها بهعنوان وسیلهای برای ارتباط بین نخها استفاده کرد. در عوض، میتوانید از اولیههای همگامسازی ماژول threading استفاده کنید.
علاوه بر این، فقط نخ اصلی مفسر اصلی مجاز به تنظیم یک مدیر سیگنال (signal handler) جدید است.
هشدار
نباید از اولیههای همگامسازی مانند threading.Lock در هندلرهای سیگنال استفاده شود. این کار میتواند به بنبستهای غیرمنتظره منجر شود.
محتویات ماژول¶
ماژول signal سه enum تعریف میکند:
-
class signal.Signals¶
enum.IntEnum مجموعهای از ثابتهای SIG* و ثابتهای CTRL_*.
-
class signal.Handlers¶
enum.IntEnum مجموعهای از ثابتهای SIG_DFL و SIG_IGN.
-
class signal.Sigmasks¶
مجموعهی enum.IntEnum از ثابتهای SIG_BLOCK، SIG_UNBLOCK و SIG_SETMASK.
متغیرهای تعریفشده در ماژول signal عبارتند از:
-
signal.SIG_DFL¶
این یکی از دو گزینهی استاندارد مدیریت سیگنال است؛ این گزینه صرفاً رفتار پیشفرض سیگنال را اعمال میکند. برای مثال، در بیشتر سیستمها رفتار پیشفرض برای SIGQUIT برونریزی core (dump core) و خروج است، در حالی که رفتار پیشفرض برای SIGCHLD صرفاً نادیده گرفتن آن است.
-
signal.SIG_IGN¶
این یک هندلر سیگنال استاندارد دیگر است که بهسادگی سیگنال دادهشده را نادیده میگیرد.
-
signal.SIGABRT¶
سیگنال خاتمه (Abort) از abort(3).
-
signal.SIGALRM¶
سیگنال زمانسنج از alarm(2).
-
signal.SIGBREAK¶
وقفه از صفحهکلید (CTRL + BREAK).
-
signal.SIGBUS¶
خطای گذرگاه (دسترسی نامعتبر به حافظه).
-
signal.SIGCHLD¶
فرایند فرزند متوقف شد یا خاتمه یافت.
-
signal.SIGCLD¶
نام مستعار برای SIGCHLD.
-
signal.SIGCONT¶
اگر فرآیند در حال حاضر متوقف است، آن را ادامه دهید
-
signal.SIGFPE¶
استثنای ممیز شناور. برای مثال، تقسیم بر صفر.
همچنین ببینید
ZeroDivisionError زمانی پرتاب میشود که دومین آرگومان یک عملیات تقسیم یا باقیمانده صفر باشد.
-
signal.SIGHUP¶
قطع ارتباط (Hangup) در پایانه کنترلکننده یا مرگ فرایند کنترلکننده شناسایی شد.
-
signal.SIGILL¶
دستورالعمل غیرمجاز.
-
signal.SIGINT¶
وقفه از صفحهکلید (CTRL + C).
اقدام پیشفرض، پرتاب KeyboardInterrupt است.
-
signal.SIGKILL¶
سیگنال کشتن (Kill signal).
نمیتوان آن را گرفت، مسدود کرد یا نادیده گرفت.
-
signal.SIGPIPE¶
پایپی شکسته: نوشتن در پایپای بدون خواننده.
اقدام پیشفرض، نادیده گرفتن سیگنال است.
-
signal.SIGPROF¶
زمانسنج پروفایلسازی منقضی شد.
-
signal.SIGQUIT¶
سیگنال خروج پایانه.
-
signal.SIGSEGV¶
خطای قطعهبندی: ارجاع نامعتبر به حافظه.
-
signal.SIGSTOP¶
توقف اجرا (قابل گرفتن یا نادیدهگرفتن نیست).
-
signal.SIGSTKFLT¶
خطای پشته در همپردازنده. هستهی لینوکس این سیگنال را پرتاب نمیکند: فقط میتواند در فضای کاربر پرتاب شود.
دسترسپذیری: Linux.
در معماریهایی که سیگنال در دسترس است. برای اطلاعات بیشتر، صفحهی man signal(7) را ببینید.
اضافه شده در نسخهی 3.11.
-
signal.SIGTERM¶
سیگنال خاتمه.
-
signal.SIGUSR1¶
سیگنال ۱ تعریفشده توسط کاربر.
-
signal.SIGUSR2¶
سیگنال ۲ تعریفشده توسط کاربر.
-
signal.SIGVTALRM¶
زمانسنج مجازی منقضی شد.
-
signal.SIGWINCH¶
سیگنال تغییر اندازهی پنجره.
-
signal.SIGXCPU¶
از محدودیت زمان CPU فراتر رفت.
-
SIG*
همه شمارههای سیگنال بهصورت نمادین تعریف شدهاند. برای مثال، سیگنال قطع ارتباط بهصورت signal.SIGHUP تعریف شده است؛ نام متغیرها دقیقاً همان نامهایی هستند که در برنامههای C استفاده میشوند، همانطور که در <signal.h> آمده است. صفحه راهنمای یونیکس برای «signal» سیگنالهای موجود را فهرست میکند (در برخی سیستمها این signal(2) است، در برخی دیگر فهرست در signal(7) قرار دارد). توجه داشته باشید که همه سیستمها مجموعه یکسانی از نامهای سیگنال را تعریف نمیکنند؛ این ماژول تنها نامهایی را تعریف میکند که سیستم آنها را تعریف کرده است.
-
signal.CTRL_C_EVENT¶
سیگنال متناظر با رویداد فشردن کلید Ctrl+C. این سیگنال را فقط میتوان با os.kill() استفاده کرد.
-
signal.CTRL_BREAK_EVENT¶
سیگنال متناظر با رویداد فشردن کلید Ctrl+Break. این سیگنال فقط میتواند با os.kill() استفاده شود.
-
signal.NSIG¶
یک بیشتر از بالاترین شمارهی سیگنال. برای دریافت شمارههای سیگنال معتبر از valid_signals() استفاده کنید.
-
signal.ITIMER_REAL¶
زمانسنج بازهای را در زمان واقعی کاهش میدهد و پس از انقضا، SIGALRM را ارسال میکند.
-
signal.ITIMER_VIRTUAL¶
زمانسنج فاصلهای را تنها زمانی که فرایند در حال اجرا است کاهش میدهد و پس از انقضا، SIGVTALRM را ارسال میکند.
-
signal.ITIMER_PROF¶
زمانسنج بازهای را هم زمانی که فرایند اجرا میشود و هم زمانی که سیستم به نمایندگی از فرایند در حال اجرا است، کاهش میدهد. این زمانسنج معمولاً همراه با ITIMER_VIRTUAL برای پروفایلگیری زمانی که برنامه در فضای کاربر و فضای هسته صرف میکند، استفاده میشود. SIGPROF پس از انقضا ارسال میشود.
-
signal.SIG_BLOCK¶
یک مقدار ممکن برای پارامتر how در pthread_sigmask() که نشان میدهد سیگنالها باید مسدود شوند.
-
signal.SIG_UNBLOCK¶
یک مقدار ممکن برای پارامتر how در pthread_sigmask() که نشان میدهد سیگنالها باید رفع مسدود شوند.
-
signal.SIG_SETMASK¶
یک مقدار ممکن برای پارامتر how در pthread_sigmask() که نشان میدهد نقاب سیگنال (signal mask) باید جایگزین شود.
ماژول signal یک استثنا تعریف میکند:
-
exception signal.ItimerError¶
برای اعلام یک خطا از پیادهسازی زیرین setitimer() یا getitimer() پرتاب میشود. در صورتی که زمانسنج بازهای نامعتبر یا زمان منفی به setitimer() داده شود، این خطا مورد انتظار است. این خطا زیرنوعی از OSError است.
اضافه شده در نسخهی 3.3: این خطا پیشتر زیرنوعی از IOError بود که اکنون نام مستعار OSError است.
ماژول signal توابع زیر را تعریف میکند:
-
signal.alarm(time)¶
اگر time غیرصفر باشد، این تابع درخواست میکند که یک سیگنال SIGALRM پس از time ثانیه به فرایند ارسال شود. هر هشدار از پیش زمانبندیشده لغو میشود (در هر زمان فقط یک هشدار میتواند زمانبندی شود). در این صورت، مقدار بازگشتی تعداد ثانیههای باقیمانده تا زمانی است که هر هشدار از پیش تنظیمشده قرار بود تحویل داده شود. اگر time صفر باشد، هشداری زمانبندی نمیشود و هر هشدار زمانبندیشده لغو میشود. اگر مقدار بازگشتی صفر باشد، در حال حاضر هشداری زمانبندی نشده است.
-
signal.getsignal(signalnum)¶
هندلر سیگنال فعلی برای سیگنال signalnum را برمیگرداند. مقدار برگرداندهشده ممکن است یک شیء پایتونی فراخوانیپذیر باشد، یا یکی از مقادیر خاص signal.SIG_IGN، signal.SIG_DFL یا None. در اینجا، signal.SIG_IGN به این معناست که سیگنال پیشتر نادیده گرفته شده است، signal.SIG_DFL به این معناست که روش پیشفرض رسیدگی به سیگنال پیشتر در حال استفاده بوده است، و None به این معناست که مدیر سیگنال پیشین از پایتون نصب نشده است.
-
signal.strsignal(signalnum)¶
توضیح سیگنال signalnum را بازمیگرداند، مانند «Interrupt» برای SIGINT. اگر signalnum توضیحی نداشته باشد، None را بازمیگرداند. اگر signalnum نامعتبر باشد، ValueError را پرتاب میکند.
-
signal.valid_signals()¶
مجموعهای از شمارههای سیگنال معتبر در این پلتفرم را برمیگرداند. اگر برخی سیگنالها برای استفادهی داخلی توسط سیستم رزرو شده باشند، این مجموعه میتواند کمتر از range(1, NSIG) باشد.
-
signal.pause()¶
باعث میشود فرآیند تا دریافت یک سیگنال متوقف شود؛ سپس هندلر مناسب فراخوانی خواهد شد. چیزی برنمیگرداند.
همچنین sigwait()، sigwaitinfo()، sigtimedwait() و sigpending() را ببینید.
-
signal.raise_signal(signum)¶
یک سیگنال به فرایند فراخوان ارسال میکند. چیزی برنمیگرداند.
-
signal.pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)¶
سیگنال sig را به فرایندی که با توصیفگر پرونده pidfd به آن اشاره شده است ارسال کنید. پایتون در حال حاضر از پارامتر siginfo پشتیبانی نمیکند؛ این پارامتر باید None باشد. آرگومان flags برای توسعههای آینده در نظر گرفته شده است؛ در حال حاضر هیچ مقدار پرچمی تعریف نشده است.
برای اطلاعات بیشتر، به صفحه راهنمای pidfd_send_signal(2) مراجعه کنید.
-
signal.pthread_kill(thread_id, signalnum)¶
سیگنال signalnum را به نخ thread_id، نخ دیگری در همان فرایند فراخواننده، ارسال کنید. نخ هدف میتواند در حال اجرای هر کدی (پایتون یا غیرپایتون) باشد. با این حال، اگر نخ هدف در حال اجرای مفسر پایتون باشد، هندلرهای سیگنال پایتون توسط نخ اصلی مفسر اصلی اجرا خواهند شد. بنابراین، تنها هدف از ارسال سیگنال به یک نخ پایتونی مشخص این است که یک فراخوانی سیستمی در حال اجرا را وادار کند تا با InterruptedError شکست بخورد.
برای دریافت یک مقدار مناسب برای thread_id، از threading.get_ident() یا ویژگی ident اشیای threading.Thread استفاده کنید.
اگر signalnum برابر ۰ باشد، هیچ سیگنالی ارسال نمیشود، اما بررسی خطا همچنان انجام میشود؛ از این میتوان برای بررسی اینکه نخ هدف هنوز در حال اجرا است یا خیر استفاده کرد.
یک رویداد حسابرسی signal.pthread_kill را با آرگومانهای thread_id و signalnum پرتاب میکند.
همچنین ببینید os.kill().
-
signal.pthread_sigmask(how, mask)¶
نقاب سیگنال نخ فراخوان را واکشی و/یا تغییر میدهد. نقاب سیگنال مجموعهای از سیگنالها است که تحویل آنها در حال حاضر برای فراخوان مسدود است. نقاب سیگنال قبلی را بهعنوان مجموعهای از سیگنالها برمیگرداند.
رفتار فراخوانی، بسته به مقدار how، به شرح زیر است.
SIG_BLOCK: مجموعه سیگنالهای مسدودشده، اجتماع مجموعه فعلی و آرگومان mask است.
SIG_UNBLOCK: سیگنالهای موجود در mask از مجموعهی فعلی سیگنالهای مسدودشده حذف میشوند. تلاش برای رفع انسداد سیگنالی که مسدود نیست، مجاز است.
SIG_SETMASK: مجموعه سیگنالهای مسدودشده به آرگومان mask تنظیم میشود.
mask مجموعهای از شمارههای سیگنال است (مانند {signal.SIGINT, signal.SIGTERM}). برای یک نقاب کامل شامل تمام سیگنالها، از valid_signals() استفاده کنید.
برای مثال، signal.pthread_sigmask(signal.SIG_BLOCK, []) نقاب سیگنال نخ فراخواننده را میخواند.
SIGKILL و SIGSTOP نمیتوانند مسدود شوند.
همچنین pause()، sigpending() و sigwait() را ببینید.
-
signal.setitimer(which, seconds, interval=0)¶
تایمر فاصلهای مشخصشده (یکی از signal.ITIMER_REAL، signal.ITIMER_VIRTUAL یا signal.ITIMER_PROF) که توسط which مشخص شده است را تنظیم میکند تا پس از seconds (گرد شده رو به بالا به میکروثانیه، متفاوت از alarm()) و پس از آن هر interval ثانیه (اگر interval غیرصفر باشد) آتش شود. تایمر فاصلهای مشخصشده توسط which را میتوان با تنظیم کردن seconds روی صفر پاک کرد.
وقتی یک زمانسنج بازهای فعال میشود، یک سیگنال به فرایند ارسال میشود. سیگنال ارسالی به زمانسنج مورد استفاده بستگی دارد؛ signal.ITIMER_REAL سیگنال SIGALRM را ارسال میکند، signal.ITIMER_VIRTUAL سیگنال SIGVTALRM را ارسال میکند، و signal.ITIMER_PROF سیگنال SIGPROF را ارسال میکند.
مقادیر قدیمی به صورت یک ۲-تایی از اعداد اعشاری برگردانده میشوند: (delay، interval).
تلاش برای ارسال یک زمانسنج بازهای (interval timer) نامعتبر باعث بروز ItimerError میشود.
تغییر یافته در نسخهی 3.15: هر عدد حقیقی را به عنوان seconds و interval میپذیرد، و محدود به اعداد صحیح یا اعشاری نیست.
-
signal.getitimer(which)¶
مقدار فعلی زمانسنج بازهای مشخصشده توسط which را برمیگرداند.
-
signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)¶
توصیفگر پرونده بیدارباش را روی fd تنظیم کنید. هرگاه سیگنالی دریافت شود که برنامهی شما برای آن هندلر سیگنال ثبت کرده است، شماره سیگنال بهصورت یک بایت در آن توصیفگر پرونده نوشته میشود. اگر برای سیگنالهای موردنظرتان مدیر سیگنال ثبت نکرده باشید، هیچ چیزی در توصیفگر پرونده بیدارباش نوشته نخواهد شد. یک کتابخانه میتواند از این قابلیت برای بیدار کردن یک فراخوانی poll یا select استفاده کند تا سیگنال بهطور کامل پردازش شود.
توصیفگر پرونده بیدارباش قبلی بازگردانده میشود (یا -1 اگر بیدارباش توصیفگر پرونده فعال نشده باشد). اگر fd برابر -1 باشد، بیدارباش توصیفگر پرونده غیرفعال میشود. اگر -1 نباشد، fd باید غیرمسدود باشد. بر عهده کتابخانه است که پیش از فراخوانی دوباره poll یا select، هر بایتی را از fd حذف کند.
هنگامی که نخها فعال باشند، این تابع فقط میتواند از نخ اصلی مفسر اصلی فراخوانی شود؛ تلاش برای فراخوانی آن از سایر نخها باعث پرتاب استثنای ValueError میشود.
دو روش رایج برای استفاده از این تابع وجود دارد. در هر دو روش، از fd برای بیدار شدن هنگام رسیدن یک سیگنال استفاده میکنید، اما این دو در نحوهی تعیین اینکه کدام سیگنال یا سیگنالها رسیدهاند، تفاوت دارند.
در رویکرد اول، دادهها را از بافر fd میخوانیم، و مقادیر بایت، شمارههای سیگنال را به شما میدهند. این روش ساده است، اما در موارد نادر ممکن است با مشکلی مواجه شود: معمولاً fd مقدار محدودی فضای بافر دارد، و اگر سیگنالهای زیادی خیلی سریع برسند، ممکن است بافر پر شود و برخی سیگنالها از دست بروند. اگر از این رویکرد استفاده میکنید، باید warn_on_full_buffer=True را تنظیم کنید، که حداقل باعث میشود هنگام از دست رفتن سیگنالها، هشداری در stderr چاپ شود.
در رویکرد دوم، از fd بیدارباش (wakeup fd) فقط برای بیدارباشها استفاده میکنیم و مقادیر واقعی بایتها را نادیده میگیریم. در این حالت، تنها چیزی که اهمیت دارد این است که بافر fd خالی است یا غیرخالی؛ پر بودن بافر بههیچوجه نشاندهندهی مشکل نیست. اگر از این رویکرد استفاده میکنید، باید warn_on_full_buffer=False را تنظیم کنید تا کاربران شما با پیامهای هشدار کاذب دچار سردرگمی نشوند.
تغییر یافته در نسخهی 3.5: در ویندوز، این تابع اکنون از دستههای سوکت نیز پشتیبانی میکند.
تغییر یافته در نسخهی 3.7: پارامتر warn_on_full_buffer افزوده شد.
-
signal.siginterrupt(signalnum, flag)¶
رفتار راهاندازی مجدد فراخوانی سیستم را تغییر میدهد: اگر flag برابر False باشد، فراخوانیهای سیستم هنگامی که با سیگنال signalnum قطع شوند دوباره راهاندازی میشوند، در غیر این صورت فراخوانیهای سیستم قطع میشوند. چیزی برنمیگرداند.
توجه داشته باشید که نصب یک هندلر سیگنال با signal()، رفتار شروع مجدد را از طریق فراخوانی ضمنی siginterrupt() با مقدار درست برای flag مربوط به سیگنال مورد نظر، به حالت قابلقطع بازنشانی میکند.
-
signal.signal(signalnum, handler)¶
هندلر سیگنال signalnum را روی تابع handler تنظیم کنید. handler میتواند یک شیء پایتونی فراخوانیپذیر باشد که دو آرگومان میپذیرد (در زیر ببینید)، یا یکی از مقادیر ویژه signal.SIG_IGN یا signal.SIG_DFL. هندلر سیگنال پیشین برگردانده خواهد شد (به توضیح getsignal() در بالا مراجعه کنید). (برای اطلاعات بیشتر، صفحهی man یونیکس signal(2) را ببینید.)
هنگامی که نخها فعال باشند، این تابع فقط میتواند از نخ اصلی مفسر اصلی فراخوانی شود؛ تلاش برای فراخوانی آن از سایر نخها باعث پرتاب استثنای ValueError میشود.
هندلر با دو آرگومان فراخوانی میشود: شمارهی سیگنال و فریم پشتهی جاری (None یا یک شیء فریم؛ برای توضیح اشیای فریم، توضیح در سلسلهمراتب نوع یا توضیحات ویژگیها در ماژول inspect را ببینید).
در ویندوز، signal() را فقط میتوان با SIGABRT، SIGFPE، SIGILL، SIGINT، SIGSEGV، SIGTERM یا SIGBREAK فراخوانی کرد. در هر حالت دیگر، یک ValueError پرتاب خواهد شد. توجه داشته باشید که همهی سیستمها مجموعهی یکسانی از نامهای سیگنال را تعریف نمیکنند؛ اگر یک نام سیگنال بهعنوان ثابت سطح ماژول SIG* تعریف نشده باشد، یک AttributeError پرتاب خواهد شد.
-
signal.sigpending()¶
مجموعه سیگنالهایی را که در انتظار تحویل به نخ فراخوان هستند (یعنی سیگنالهایی که در حین مسدود بودن پرتاب شدهاند) بررسی کنید. مجموعه سیگنالهای در انتظار را برگردانید.
همچنین ببینید pause()، pthread_sigmask() و sigwait().
-
signal.sigwait(sigset)¶
اجرای نخ فراخوان را تا تحویل یکی از سیگنالهای مشخصشده در مجموعه سیگنال sigset معلق میکند. این تابع سیگنال را میپذیرد (آن را از فهرست سیگنالهای در انتظار حذف میکند) و شماره سیگنال را برمیگرداند.
همچنین ببینید pause()، pthread_sigmask()، sigpending()، sigwaitinfo() و sigtimedwait().
-
signal.sigwaitinfo(sigset)¶
اجرای نخ فراخوان را تا تحویل یکی از سیگنالهای مشخصشده در مجموعه سیگنال sigset معلق میکند. تابع سیگنال را میپذیرد و آن را از فهرست سیگنالهای در انتظار حذف میکند. اگر یکی از سیگنالهای درون sigset از قبل برای نخ فراخوان در انتظار باشد، تابع بلافاصله همراه با اطلاعاتی درباره آن سیگنال بازگشت میکند. هندلر سیگنال برای سیگنال تحویلشده فراخوانی نمیشود. اگر تابع توسط سیگنالی که در sigset نیست قطع شود، یک InterruptedError را پرتاب میکند.
مقدار بازگشتی یک شیء است که دادههای موجود در ساختار siginfo_t را نشان میدهد، یعنی: si_signo، si_code، si_errno، si_pid، si_uid، si_status، si_band.
همچنین ببینید pause()، sigwait() و sigtimedwait().
تغییر یافته در نسخهی 3.5: این تابع اکنون در صورتی که توسط سیگنالی که در sigset نیست قطع شود و هندلر سیگنال استثنایی پرتاب نکند، دوباره اجرا میشود (برای دلیل این موضوع PEP 475 را ببینید).
-
signal.sigtimedwait(sigset, timeout)¶
مانند sigwaitinfo()، اما یک آرگومان timeout اضافی برای تعیین مهلت زمانی میگیرد. اگر timeout بهصورت 0 تعیین شود، یک پایش (poll) انجام میشود. در صورت رخ دادن مهلت زمانی، None را برمیگرداند.
همچنین ببینید pause()، sigwait() و sigwaitinfo().
تغییر یافته در نسخهی 3.5: این تابع اکنون در صورتی که با سیگنالی خارج از sigset قطع شود و هندلر سیگنال استثنایی پرتاب نکند، با timeout دوباره محاسبهشده مجدداً اجرا میشود (برای دلیل، PEP 475 را ببینید).
تغییر یافته در نسخهی 3.15: هر عدد حقیقی را به عنوان timeout میپذیرد، نه فقط عدد صحیح یا عدد اعشاری.
مثالها¶
در اینجا یک برنامه نمونه حداقلی آمده است. این برنامه از تابع alarm() برای محدود کردن زمان انتظار برای باز کردن یک پرونده استفاده میکند؛ این کار زمانی مفید است که پرونده مربوط به یک دستگاه سریال باشد که ممکن است روشن نباشد، وضعیتی که در حالت عادی باعث میشود os.open() بهطور نامحدود معلق بماند. راهحل، تنظیم یک زنگ ۵ ثانیهای پیش از باز کردن پرونده است؛ اگر عملیات بیش از حد طول بکشد، سیگنال زنگ ارسال خواهد شد و هندلر استثنایی را پرتاب میکند.
import signal, os
def handler(signum, frame):
signame = signal.Signals(signum).name
print(f'Signal handler called with signal {signame} ({signum})')
raise OSError("Couldn't open device!")
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)
signal.alarm(0) # Disable the alarm
یادداشتی درباره SIGPIPE¶
هدایت خروجی برنامهتان به ابزارهایی مانند head(1) باعث میشود هنگامی که دریابندهی خروجی استاندارد آن زودتر بسته شود، یک سیگنال SIGPIPE به فرایند شما ارسال شود. این امر به استثنایی مانند BrokenPipeError: [Errno 32] Broken pipe منجر میشود. برای مدیریت این حالت، نقطه ورود خود را بهشکل زیر بپوشانید تا این استثنا را بگیرد:
import os
import sys
def main():
try:
# simulate large output (your code replaces this loop)
for x in range(10000):
print("y")
# flush output here to force SIGPIPE to be triggered
# while inside this try block.
sys.stdout.flush()
except BrokenPipeError:
# Python flushes standard streams on exit; redirect remaining output
# to devnull to avoid another BrokenPipeError at shutdown
devnull = os.open(os.devnull, os.O_WRONLY)
os.dup2(devnull, sys.stdout.fileno())
sys.exit(1) # Python exits with error code 1 on EPIPE
if __name__ == '__main__':
main()
برای اجتناب از BrokenPipeError، رفتار SIGPIPE را روی SIG_DFL تنظیم نکنید. این کار باعث میشود برنامه شما هرگاه اتصال سوکتی در حالی که برنامه هنوز در حال نوشتن روی آن است قطع شود، بهطور غیرمنتظرهای خارج شود.
یادداشتی دربارهی هندلرهای سیگنال و استثناها¶
اگر یک هندلر سیگنال استثنایی را پرتاب کند، آن استثنا به نخ اصلی منتقل میشود و ممکن است پس از هر دستور bytecode پرتاب شود. بهویژه، ممکن است KeyboardInterrupt در هر نقطهای از اجرا رخ دهد. نمیتوان بیشتر کدهای پایتون، از جمله کتابخانه استاندارد، را در برابر این حالت مقاوم کرد، و بنابراین یک KeyboardInterrupt (یا هر استثنای دیگری که از یک مدیر سیگنال ناشی میشود) ممکن است در موارد نادر برنامه را در وضعیت غیرمنتظرهای قرار دهد.
برای روشنکردن این مسئله، کد زیر را در نظر بگیرید:
class SpamContext:
def __init__(self):
self.lock = threading.Lock()
def __enter__(self):
# If KeyboardInterrupt occurs here, everything is fine
self.lock.acquire()
# If KeyboardInterrupt occurs here, __exit__ will not be called
...
# KeyboardInterrupt could occur just before the function returns
def __exit__(self, exc_type, exc_val, exc_tb):
...
self.lock.release()
برای بسیاری از برنامهها، بهویژه آنهایی که صرفاً میخواهند در صورت بروز KeyboardInterrupt خارج شوند، این یک مشکل نیست، اما برنامههای کاربردی پیچیده یا نیازمند قابلیت اطمینان بالا باید از پرتاب استثنا از درون هندلرهای سیگنال خودداری کنند. آنها همچنین باید از گرفتن KeyboardInterrupt بهعنوان وسیلهای برای خاموش شدن ایمن خودداری کنند. در عوض، باید هندلر SIGINT اختصاصی خود را نصب کنند. در زیر مثالی از یک سرور HTTP آمده است که از KeyboardInterrupt اجتناب میکند:
import signal
import socket
from selectors import DefaultSelector, EVENT_READ
from http.server import HTTPServer, SimpleHTTPRequestHandler
interrupt_read, interrupt_write = socket.socketpair()
def handler(signum, frame):
print('Signal handler called with signal', signum)
interrupt_write.send(b'\0')
signal.signal(signal.SIGINT, handler)
def serve_forever(httpd):
sel = DefaultSelector()
sel.register(interrupt_read, EVENT_READ)
sel.register(httpd, EVENT_READ)
while True:
for key, _ in sel.select():
if key.fileobj == interrupt_read:
interrupt_read.recv(1)
return
if key.fileobj == httpd:
httpd.handle_request()
print("Serving on port 8000")
httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
serve_forever(httpd)
print("Shutdown...")
© حق نشر 2001 Python Software Foundation.
این صفحه تحت مجوز بنیاد نرمافزار پایتون نسخه ۲ منتشر شده است.
مثالها، دستورالعملها، و سایر کدهای موجود در مستندات همچنین تحت مجوز بدون بند BSD منتشر شدهاند.
برای اطلاعات بیشتر به تاریخچه و مجوز مراجعه کنید.
بنیاد نرمافزار پایتون یک شرکت غیرانتفاعی است.
لطفاً کمک مالی کنید.
آخرین بهروزرسانی در نوامبر 12, 2026 (06:19 UTC).
آیا اشکالی یافتید؟
ساخته شده با Sphinx 9.1.0.
|