الفرق بين المراجعتين لصفحة: «Ruby/Thread/handle interrupt»
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: التابع <code>handle_interrupt</code> الخاص بالصنف <code>Thread</code> في روبي}}</noinclude> تصنيف: Ruby...' |
جميل-بيلوني (نقاش | مساهمات) ط مراجعة وتدقيق. |
||
(مراجعتان متوسطتان بواسطة مستخدم واحد آخر غير معروضتين) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE: التابع <code>handle_interrupt | <noinclude>{{DISPLAYTITLE: التابع <code>Thread.handle_interrupt</code> في روبي}}</noinclude> | ||
[[تصنيف: Ruby]] | [[تصنيف: Ruby]] | ||
[[تصنيف: Ruby Method]] | [[تصنيف: Ruby Method]] | ||
سطر 5: | سطر 5: | ||
يغير التابع <code>handle_interrupt</code> توقيت المقاطعة غير المتزامنة (asynchronous interrupt timing). | يغير التابع <code>handle_interrupt</code> توقيت المقاطعة غير المتزامنة (asynchronous interrupt timing). | ||
يعني | المقاطعة (interrupt) يعني الحدث غير المتزامن (asynchronous event) والإجراء المقابل <code>[[Ruby/Thread/raise|raise]]</code> و <code>[[Ruby/Thread/kill|kill]]</code> وإشارة المسك (signal trap، غير مدعومة حاليًا) وعملية إنهاء [[Ruby/Thread|المهمة الفرعية]] الرئيسية (عند إنهاء [[Ruby/Thread|المهمة الفرعية]] الرئيسية، فسيتم إنهاء كل [[Ruby/Thread|المهام الفرعية]] الأخرى). | ||
==البنية العامة== | |||
<syntaxhighlight lang="ruby">handle_interrupt(hash) { ... } → result of the block</syntaxhighlight>يحتوي المعامل <code>hash</code> المعطى على أزواج على شاكلة <code>ExceptionClass => :TimingSymbol</code> إذ <code>ExceptionClass</code> هو مقاطعة (interrupt) المٌعالج من قبل الكتلة المعطاة. أما <code>TimingSymbol</code> فيمكن أن يكون أحد الرموز التالية: | |||
:TimingSymbol</code> | * <code>:immediate</code> - يستدعي المقاطعات على الفور. | ||
* <code>:on_blocking</code> - يستدعي المقاطعات أثناء الحالة <code>BlockingOperation</code>. | |||
<code>:immediate</code> | * <code>:never</code> - لا يستدعي جميع المقاطعات أبدًا. | ||
<code>BlockingOperation</code> تعني أن العملية ستقوم بتعطيل [[Ruby/Thread|المهمة الفرعية]] المستدعية (calling thread)، مثل <code>read</code> و <code>write</code>. في إصدار CRuby ، ستكون <code>BlockingOperation</code> أي عملية تُنفَّذ بدون قفل الآلة الافتراضية العام (Global VM Lock أو اختصارًا GVL). | |||
يستدعي | |||
<code>:on_blocking</code> | |||
يستدعي | |||
<code>:never</code> | |||
لا يستدعي جميع | |||
المقاطعات غير المتزامنة المقنعة (Masked asynchronous interrupts) ستُؤجل إلى حين تمكينها. | |||
هذا التابع مشابه للتعبير <code>sigprocmask(3)</code>. | |||
إذا كنت بحاجة إلى إجراء اتصالات بين [[Ruby/Thread| | == ملاحظة == | ||
يصعب استخدام المقاطعات غير المتزامنة. إذا كنت بحاجة إلى إجراء اتصالات بين [[Ruby/Thread|المهام الفرعية]]، فالرجاء استخدام طريقة أخرى، مثل [[Ruby/Queue|الطوابير]]. وإن كنت مصرّا على استخدام هذا التابع، فاستخدمه، لكن مع فهم عميق لخصائصه. | |||
== الاستخدام == | |||
في المثال التالي، يمكننا الاحتراز من استثناءات <code>[[Ruby/Thread/raise|raise]]</code>. | |||
باستخدام رمز التوقيت (TimingSymbol) <code>:never</code>، سيتم تجاهل الاستثناء <code>[[Ruby/RuntimeError|RuntimeError]]</code> دائما في الكتلة الأولى من [[Ruby/Thread|المهمة الفرعية]] الرئيسية. في كتلة <code>handle_interrupt</code> الثانية، يمكن معالجة الاستثناءات <code>[[Ruby/RuntimeError|RuntimeError]]</code>:<syntaxhighlight lang="ruby">th = Thread.new do | |||
<syntaxhighlight lang="ruby">th = Thread.new do | |||
Thread.handle_interrupt(RuntimeError => :never) { | Thread.handle_interrupt(RuntimeError => :never) { | ||
begin | begin | ||
سطر 88: | سطر 37: | ||
Thread.pass | Thread.pass | ||
# ... | # ... | ||
th.raise "stop"</syntaxhighlight> | th.raise "stop"</syntaxhighlight>بينما نتجاهل الاستثناء <code>[[Ruby/RuntimeError|RuntimeError]]</code>، سيكون من الآمن كتابة تعليمات تخصيص الموارد (resource allocation). بعد ذلك ستكون كتلة التأمين (ensure block) هي المكان المناسب لتحرير (deallocate) الموارد بأمان. | ||
== التحرز من الاستثناء <code>Timeout::Error</code> == | |||
* التابع <code>[[Ruby/Thread/ | في المثال التالي، سنحترز من الاستثناء <code>Timeout::Error</code>. سيساعد هذا على منع هدر الموارد عند حدوث هذا الاستثناء أثناء كتلة تأمين (ensure clause) عادية. في هذا المثال، سنستعين بالمكتبة القياسية <code>Timeout</code> في <code>lib/timeout.rb</code>.<syntaxhighlight lang="ruby">require 'timeout' | ||
Thread.handle_interrupt(Timeout::Error => :never) { | |||
timeout(10){ | |||
# Timeout::Error doesn't occur here | |||
Thread.handle_interrupt(Timeout::Error => :on_blocking) { | |||
# possible to be killed by Timeout::Error | |||
# while blocking operation | |||
} | |||
# Timeout::Error doesn't occur here | |||
} | |||
}</syntaxhighlight>في الجزء الأول من كتلة <code>timeout</code> ، يمكننا الاعتماد على حقيقة أن الاستثناء <code>Timeout::Error</code> سيتم تجاهله. ثم في كتلة <code>Timeout::Error =>on_blocking</code>، فأي عملية تُعطل [[Ruby/Thread|المهمة الفرعية]] المستدعية (calling thread) ستكون عرضة للاستثناء <code>Timeout::Error</code>. | |||
== إعدادات التحكم في المكدس == | |||
من الممكن تكديس مستويات متعددة من كتل <code>handle_interrupt</code> من أجل التحكم في عدة كائنات من النوع <code>ExceptionClass</code> و <code>TimingSymbol</code> في وقت واحد.<syntaxhighlight lang="ruby">Thread.handle_interrupt(FooError => :never) { | |||
Thread.handle_interrupt(BarError => :never) { | |||
# FooError and BarError are prohibited. | |||
} | |||
}</syntaxhighlight> | |||
== الوراثة من <code>ExceptionClass</code> == | |||
سيتم أخذ كافة الاستثناءات الموروثة من الوسيط <code>ExceptionClass</code> بعين الاعتبار. | |||
<syntaxhighlight lang="ruby">Thread.handle_interrupt(Exception => :never) { | |||
# all exceptions inherited from Exception are prohibited. | |||
}</syntaxhighlight> | |||
==القيمة المُعادة== | |||
تعاد نتيجة الكتلة المعطاة. | |||
==انظر أيضًا== | |||
* التابع <code>[[Ruby/Thread/fork|fork]]</code>: ينشئ عملية فرعية جديدة بشكل مكافئ للتابع <code>new</code>. | |||
* التابع <code>[[Ruby/Thread/kill|kill]]</code>: ينهي العملية الفرعية المعطاة. | |||
==مصادر== | ==مصادر== | ||
*[http://ruby-doc.org/core-2.5.1/Thread.html#method-c-handle_interrupt قسم | *[http://ruby-doc.org/core-2.5.1/Thread.html#method-c-handle_interrupt قسم التابع handle_interrupt في الصنف Thread في توثيق روبي الرسمي.] |
المراجعة الحالية بتاريخ 12:22، 5 ديسمبر 2018
يغير التابع handle_interrupt
توقيت المقاطعة غير المتزامنة (asynchronous interrupt timing).
المقاطعة (interrupt) يعني الحدث غير المتزامن (asynchronous event) والإجراء المقابل raise
و kill
وإشارة المسك (signal trap، غير مدعومة حاليًا) وعملية إنهاء المهمة الفرعية الرئيسية (عند إنهاء المهمة الفرعية الرئيسية، فسيتم إنهاء كل المهام الفرعية الأخرى).
البنية العامة
handle_interrupt(hash) { ... } → result of the block
يحتوي المعامل hash
المعطى على أزواج على شاكلة ExceptionClass => :TimingSymbol
إذ ExceptionClass
هو مقاطعة (interrupt) المٌعالج من قبل الكتلة المعطاة. أما TimingSymbol
فيمكن أن يكون أحد الرموز التالية:
-
:immediate
- يستدعي المقاطعات على الفور. -
:on_blocking
- يستدعي المقاطعات أثناء الحالةBlockingOperation
. -
:never
- لا يستدعي جميع المقاطعات أبدًا.
BlockingOperation
تعني أن العملية ستقوم بتعطيل المهمة الفرعية المستدعية (calling thread)، مثل read
و write
. في إصدار CRuby ، ستكون BlockingOperation
أي عملية تُنفَّذ بدون قفل الآلة الافتراضية العام (Global VM Lock أو اختصارًا GVL).
المقاطعات غير المتزامنة المقنعة (Masked asynchronous interrupts) ستُؤجل إلى حين تمكينها.
هذا التابع مشابه للتعبير sigprocmask(3)
.
ملاحظة
يصعب استخدام المقاطعات غير المتزامنة. إذا كنت بحاجة إلى إجراء اتصالات بين المهام الفرعية، فالرجاء استخدام طريقة أخرى، مثل الطوابير. وإن كنت مصرّا على استخدام هذا التابع، فاستخدمه، لكن مع فهم عميق لخصائصه.
الاستخدام
في المثال التالي، يمكننا الاحتراز من استثناءات raise
.
باستخدام رمز التوقيت (TimingSymbol) :never
، سيتم تجاهل الاستثناء RuntimeError
دائما في الكتلة الأولى من المهمة الفرعية الرئيسية. في كتلة handle_interrupt
الثانية، يمكن معالجة الاستثناءات RuntimeError
:
th = Thread.new do
Thread.handle_interrupt(RuntimeError => :never) {
begin
# You can write resource allocation code safely.
Thread.handle_interrupt(RuntimeError => :immediate) {
# ...
}
ensure
# You can write resource deallocation code safely.
end
}
end
Thread.pass
# ...
th.raise "stop"
بينما نتجاهل الاستثناء RuntimeError
، سيكون من الآمن كتابة تعليمات تخصيص الموارد (resource allocation). بعد ذلك ستكون كتلة التأمين (ensure block) هي المكان المناسب لتحرير (deallocate) الموارد بأمان.
التحرز من الاستثناء Timeout::Error
في المثال التالي، سنحترز من الاستثناء Timeout::Error
. سيساعد هذا على منع هدر الموارد عند حدوث هذا الاستثناء أثناء كتلة تأمين (ensure clause) عادية. في هذا المثال، سنستعين بالمكتبة القياسية Timeout
في lib/timeout.rb
.
require 'timeout'
Thread.handle_interrupt(Timeout::Error => :never) {
timeout(10){
# Timeout::Error doesn't occur here
Thread.handle_interrupt(Timeout::Error => :on_blocking) {
# possible to be killed by Timeout::Error
# while blocking operation
}
# Timeout::Error doesn't occur here
}
}
في الجزء الأول من كتلة timeout
، يمكننا الاعتماد على حقيقة أن الاستثناء Timeout::Error
سيتم تجاهله. ثم في كتلة Timeout::Error =>on_blocking
، فأي عملية تُعطل المهمة الفرعية المستدعية (calling thread) ستكون عرضة للاستثناء Timeout::Error
.
إعدادات التحكم في المكدس
من الممكن تكديس مستويات متعددة من كتل handle_interrupt
من أجل التحكم في عدة كائنات من النوع ExceptionClass
و TimingSymbol
في وقت واحد.
Thread.handle_interrupt(FooError => :never) {
Thread.handle_interrupt(BarError => :never) {
# FooError and BarError are prohibited.
}
}
الوراثة من ExceptionClass
سيتم أخذ كافة الاستثناءات الموروثة من الوسيط ExceptionClass
بعين الاعتبار.
Thread.handle_interrupt(Exception => :never) {
# all exceptions inherited from Exception are prohibited.
}
القيمة المُعادة
تعاد نتيجة الكتلة المعطاة.
انظر أيضًا
- التابع
fork
: ينشئ عملية فرعية جديدة بشكل مكافئ للتابعnew
. - التابع
kill
: ينهي العملية الفرعية المعطاة.