كيف يمكنك إغلاق التطبيق عندما يكون بعض Waithandle في منتصف مكالمة إلى WiTeOne؟

StackOverflow https://stackoverflow.com/questions/3087683

سؤال

هل هناك طريقة قياسية لإغلاق تطبيق "نظيف" بينما البعض WaitHandle قد تكون الكائنات في حالة دعوة حظر حالية إلى WaitOne?

على سبيل المثال ، قد يكون هناك موضوع خلفية يدور بطريقة كهذه:

while (_request.WaitOne())
{
    try
    {
        _workItem.Invoke();
    }
    finally
    {
        OnWorkCompleted();
    }
}

لا أرى أي طريقة واضحة للتخلص من هذا الموضوع دون الاتصال Thread.Abort (الذي لا مثبط له). الدعوة Close على ال _request كائن (An AutoResetEvent) ، ومع ذلك ، سوف يرمي استثناء.

حاليا ، الخيط الذي يدير هذه الحلقة له IsBackground تم تعيين الممتلكات إلى true, ، وهكذا التطبيق يبدو للإغلاق بشكل صحيح. لكن منذ WaitHandle الأدوات IDisposable, ، لست متأكدًا مما إذا كان هذا يعتبر كوشير أو إذا كان يجب التخلص من هذا الكائن بالفعل قبل خروج التطبيق.

هل هذا تصميم سيء؟ إذا لم يكن كذلك ، كيف يتم التعامل مع هذا السيناريو عادة؟

هل كانت مفيدة؟

المحلول

تحديد إضافي WaitHandle اتصل _terminate سيشير ذلك إلى طلب لإنهاء الحلقة ثم استخدامه WaitHandle.WaitAny بدلاً من WaitHandle.WaitOne.

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}

نصائح أخرى

عندما يكون الخيط يحظر (بغض النظر عن ما يحظره) يمكنك الاتصال Thread.Interrupt() هذا سوف يسبب الاستثناء ThreadInterruptedException (أعتقد ، قد يكون الأمر مختلفًا بعض الشيء) يمكنك التعامل مع هذا الاستثناء على الخيط نفسه والقيام بأي تنظيف متاح.

تجدر الإشارة إلى أن الخيط سوف يرمي فقط ThreadInterruptedException عندما يكون الحظر ، إذا لم يتم حظره ، فلن يتم إلقاؤه حتى يحاول حظره التالي.

هذه هي الطريقة "الآمنة" لإنهاء الخيوط مما قرأته حول هذا الموضوع.

تجدر الإشارة أيضًا إلى: إذا قام الكائن بتنفيذ كل من idisposable و finializer (الذي سيفعله إذا كان يستخدم موارد غير مُدارة) ، فسيتصل GC بـ Finalizer الذي يستدعي عادة التخلص منه. عادة هذا غير محدد. ومع ذلك ، يمكنك ضمان أن يتم استدعاء مخرج الطلب. فقط في ظروف خاصة جدا لم يفعلوا ذلك. (بيئة .NET تنهي استثناء مثل StackOverflowException هذا خطئ)

تعيين IsBackground خاصية ل true... يجب أن تغلق الخيط تلقائيًا عند انتهاء تطبيقك.

بالتناوب ، يمكنك مقاطعة الخيط عن طريق الاتصال Thread.Interrupt والتعامل مع ThreadInterruptedException. فكرة أخرى هي الاتصال _request.Set() وجعل الحلقة أثناء حلقة تحقق من علامة متطايرة لتحديد ما إذا كان التطبيق يغلق أو إذا كان يجب أن يستمر:

private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
    //...
}

// somewhere else in the app
_running = false;
_request.Set();

أعتقد أن نظام التشغيل سيتم تنظيفه بعد انتهاء العملية. نظرًا لأن خيطك يتم تمييزه كما isBackground ، فإن CLR سينهي العملية وجميع المواضيع في الداخل ، لذلك ليست هذه مشكلة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top