معالجة الإشارات C
في مكتبة C القياسية ، تحدد معالجة الإشارات كيفية تعامل البرنامج مع الإشارات المختلفة أثناء تنفيذه. يمكن للإشارة أن تُبلغ عن سلوك استثنائي داخل البرنامج (مثل القسمة على صفر )، أو يمكن للإشارة أن تُبلغ عن حدث غير متزامن خارج البرنامج (مثل قيام شخص ما بالضغط على مفتاح تنبيه تفاعلي على لوحة المفاتيح).
الإشارات القياسية
يحدد معيار C ست إشارات فقط. جميعها مُعرّفة في ملف الرأس <signal.h>( <csignal>): [ 1 ]
SIGABRT– "إجهاض"، إنهاء غير طبيعي.SIGFPE– استثناء الفاصلة العائمة .SIGILL– تعليمات "غير قانونية" وغير صالحة.SIGINT– "مقاطعة"، طلب انتباه تفاعلي يتم إرساله إلى البرنامج.SIGSEGV– " انتهاك تجزئة الذاكرة "، وصول غير صالح إلى الذاكرة.SIGTERM– "إنهاء"، تم إرسال طلب إنهاء إلى البرنامج.
قد تُحدد إشارات إضافية في <signal.h>رأس الملف بواسطة التطبيق. على سبيل المثال، تُعرّف أنظمة التشغيل يونكس والأنظمة الشبيهة بيونكس (مثل لينكس ) أكثر من 15 إشارة إضافية؛ انظر إشارة يونكس . [ 2 ]
تصحيح الأخطاء
SIGTRAPلأغراض تصحيح الأخطاء. وهو يعتمد على النظام الأساسي ويمكن استخدامه على أنظمة التشغيل الشبيهة بنظام يونكس .
التعامل مع
يمكن توليد الإشارة عن طريق استدعاء الدوال raise()أو kill()استدعاءات النظام. raise()ترسل إشارة إلى العملية الحالية، kill()وترسل إشارة إلى عملية محددة.
معالج الإشارة هو دالة تستدعيها بيئة التشغيل عند حدوث الإشارة المقابلة. تقوم بيئة التشغيل بتعليق تنفيذ البرنامج حتى يعود معالج الإشارة أو يستدعي دالة أخرى longjmp().
يمكن ضبط معالجات الإشارات باستخدام signal()أو . تم تغيير sigaction()سلوك عدة مرات عبر التاريخ، لذا يُنصح بتجنب استخدامه. [ 3 ] وهو قابل للنقل فقط عند استخدامه لضبط حالة الإشارة إلى SIG_DFL أو SIG_IGN. يمكن تحديد معالجات الإشارات لجميع الإشارات باستثناء إشارتين ( لا يمكن التقاط أو حظر أو تجاهل SIGKILL و SIGSTOP ).signal()
إذا أبلغت الإشارة عن خطأ داخل البرنامج (ولم تكن الإشارة غير متزامنة)، فيمكن لمعالج الإشارة أن ينهي عمله عن طريق استدعاء abort()، exit()أو longjmp().
الوظائف
| وظيفة | وصف |
|---|---|
raise | يرسل إشارة مصطنعة إلى العملية المستدعِية |
kill | يرسل إشارة بشكل مصطنع إلى عملية محددة |
signal | يحدد الإجراء المتخذ عندما يتلقى البرنامج إشارة معينة |
مثال على الاستخدام
#include <signal.h> #include <stdio.h> #include <stdlib.h>volatile sig_atomic_t status = 0 ;static void catch_function ( int signo ) { status = signo ; }int main ( void ) { // تعيين الدالة أعلاه كمعالج إشارة SIGINT: if ( signal ( SIGINT , catch_function ) == SIG_ERR ) { fprintf ( stderr , "حدث خطأ أثناء تعيين معالج الإشارة. \n " ); return EXIT_FAILURE ; } printf ( "جارٍ رفع إشارة الانتباه التفاعلي." ); if ( raise ( SIGINT )) { fprintf ( stderr , "خطأ في رفع الإشارة. \n " ); return EXIT_FAILURE ; } if ( status == SIGINT ) { printf ( "تم التقاط إشارة الانتباه التفاعلي." ); } printf ( "جارٍ الخروج." ); return EXIT_SUCCESS ; // الخروج بعد رفع الإشارة }لغات أخرى
لغة سي++
تُستخدم إشارات C تقليديًا بنفس الطريقة في C++ كما في C. ومع ذلك، يمكن أيضًا كتابة أغلفة لاستخدام نمط RAII .
تصدير الوحدة النمطية ويكيبيديا . أمثلة ؛استيراد < csignal > ; // ضروري للحصول على وحدات الماكرو استيراد std ;باستخدام std :: function ؛تصدير مساحة الاسم ويكيبيديا :: أمثلة {class Signal { private : using Handler = function < void ( int ) > ; int sig ; public : static constexpr int ABRT = SIGABRT ; static constexpr int FPE = SIGFPE ; static constexpr int ILL = SIGILL ; static constexpr int INT = SIGINT ; static constexpr int SEGV = SIGSEGV ; static constexpr int TERM = SIGTERM ; static constexpr int DFL = SIGDFL ; static constexpr int IGN = SIGIGN ; static constexpr int ERR = SIGERR ;إشارة صريحة ( int sig ) : sig { sig } {}[[ nodiscard ]] int getSignal () const noexcept { return sig ; }مقبض المعالج ( Handler Handler ) const noexcept { return std :: signal ( sig , Handler ); }int raise () const noexcept { return std :: raise ( sig ); } };}ويمكن القيام بذلك أيضًا باستخدام Boost ، باستخدام الفئة boost::asio::signal_set.
سي شارب
يمكن استخدام إشارات C مع P/Invoke و Mono.Unix.Native.Syscall.
جافا
يمكن استخدام إشارات C بشكل غير رسمي في لغة Java ، من الوحدة النمطيةjdk.unsupported ، مع فئات JVM الداخلية sun.misc.Signalوالواجهة sun.misc.SignalHandler. [ 4 ]
package org.wikipedia.example ;استيراد sun.misc.Signal ؛ استيراد sun.misc.SignalHandler ؛public class Example { public static void main ( String [] args ) { SignalHandler handler = new SignalHandler () { public void handle ( Signal sig ) { boolean handled = handlers . get ( type ). handle ( type ); if ( ! handled ) { if ( type . getDefaultAction () == SignalType . DefaultAction . IGNORE ) { SignalHandler . SIG_IGN . handle ( sig ); } else { SignalHandler . SIG_DFL . handle ( sig ); } } } }; Signal . handle ( new Signal ( "INT" ), handler ); } }الصدأ
يمكن استخدام الإشارات مع حزمة signal_hook في لغة Rust. [ 5 ]
استخدم std :: process ؛ استخدم std :: thread ؛ استخدم std :: time :: Duration ؛استخدم signal_hook :: consts :: signal :: * ; استخدم signal_hook :: iterator :: Signals ;fn main () { let mut signals : Signals = Signals :: new ( & [ SIGINT , SIGTERM ]). expect ( "فشل في إعداد معالجة الإشارة" );thread :: spawn ( move || { for signal in signals . forever () { match signal { SIGINT => { println! ( "تم استلام SIGINT (Ctrl+C). جارٍ الخروج بسلاسة." ); process :: exit ( 0 ); } SIGTERM => { println! ( "تم استلام SIGTERM. جارٍ الخروج بسلاسة." ); process :: exit ( 0 ); } _ => unreachable! (), } } });loop { println! ( "جاري التشغيل..." ); thread :: sleep ( Duration :: from_secs ( 2 )); } }انظر أيضاً
مراجع
- ↑ مواصفات ISO/IEC 9899:1999 (PDF) . صفحة 258، الفقرة 7.14 معالجة الإشارات .
- ↑ "مواصفات المجموعة المفتوحة الأساسية، الإصدار 6 - signal.h - الإشارات" . تم الاطلاع عليه بتاريخ 10 يناير 2012 .
- ↑ https://man7.org/linux/man-pages/man2/signal.2.html صفحة دليل Signal(2)
- ↑ "Signal (Java Platform SE 9)" . cr.openjdk.org . OpenJDK . تم الاطلاع عليه بتاريخ 10 أكتوبر 2025 .
- ↑ "signal_hook - Rust" . docs.rs . 9 مايو 2025.
- مكتبة C القياسية
