هل أحتاج إلى الاتصال عن قرب () على ManualResetevent؟
-
19-09-2019 - |
سؤال
لقد كنت أقرأ على .NET الخيوط وكان يعمل على بعض الكود الذي يستخدم manualresetevent.. وبعد لقد وجدت الكثير من عينات التعليمات البرمجية على الإنترنت. ومع ذلك، عند قراءة الوثائق ل whithandle., رأيت ما يلي:
waithandle تنفذ نمط التخلص من النمط. انظر تنفيذ الانتهاء والتخلص لتنظيف الموارد غير المدارة.
لا يبدو أن أيا من العينات تدعو. close () على كائنات manualresetevent التي تنشئها، حتى لطيف العودية والتزامن مقالة من بلوق pfxteam (يحرر - هذا لديه كتلة باستخدام فاتني). هل هذا إشراف مثالي فقط، أم لا يحتاج؟ أنا فضولي لأن waithandle "يثبط الكائنات الخاصة بنظام التشغيل،" لذلك يمكن أن يكون هناك تسرب الموارد بسهولة.
المحلول
بشكل عام، إذا كان كائن ينفذ IDisposable
يفعل ذلك لسبب ما ويجب أن تتصل Dispose
(أو Close
, ، كما قد تكون الحالة). في المثال أنت موقع، ملفوفة manualresetevent داخل using
بيان، والتي سوف "تلقائيا" التعامل مع الدعوة Dispose
. وبعد في هذه الحالة، Close
مرادف Dispose
(وهذا صحيح في معظم IDisposable
التطبيقات التي توفر Close
طريقة).
الرمز من المثال:
using (var mre = new ManualResetEvent(false))
{
...
}
يتوسع إلى
var mre = new ManualResetEvent(false);
try
{
...
}
finally
{
((IDispoable)mre).Dispose();
}
نصائح أخرى
لقد أحالت مؤخرا مقتطفات من C # 4.0 باختصار: المرجع النهائي بقلم جوزيف الباهر، بن البحري. في الصفحة 834، في الفصل 21: خيوط هناك قسم يتحدث عن هذا.
التخلص من مقابض الانتظار
بمجرد الانتهاء من مقبض الانتظار، يمكنك الاتصال بها يغلق طريقة لتحرير مورد نظام التشغيل. بدلا من ذلك، يمكنك ببساطة إسقاط جميع المراجع إلى مقبض الانتظار والسماح بمجمع القمامة للقيام بعملك في وقت لاحق في وقت لاحق (ينفذ مقابض الانتظار نمط التخلص حيث استدعاء النهائي يغلق). هذا هو واحد من السيناريوهات القليلة حيث الاعتماد على هذه النسخة الاحتياطية مقبولة (يمكن القول)، لأن مقابض الانتظار لها عبء نظام التشغيل الخفيف (يعتمد المندوبون غير المتزامنين على هذه الآلية بالضبط في إطلاق سراحهم IASYNCRESULT'S انتظار مقبض).
يتم إصدار مقابض الانتظار تلقائيا عند تفريغ مجال التطبيق.
يتم التعامل مع إغلاق داخل تخلص من depalresetevent، وهذا ما يسمى ببيان "استخدام".
http://msdn.microsoft.com/en-us/library/yh598w02٪28VS.100٪29.aspx.
سوف تلاحظ الكود
using (var mre = new ManualResetEvent(false))
{
// Process the left child asynchronously
ThreadPool.QueueUserWorkItem(delegate
{
Process(tree.Left, action);
mre.Set();
});
// Process current node and right child synchronously
action(tree.Data);
Process(tree.Right, action);
// Wait for the left child
mre.WaitOne();
}
يستخدم الكلمة الأساسية "باستخدام". يستدعي هذا تلقائيا طريقة التخلص عند الانتهاء حتى إذا أرقى التعليمات البرمجية استثناء.
لقد استخدمت ManualResetEvent
كثيرا ولا أعتقد أنني استخدمت ذلك من أي وقت مضى داخل طريقة واحدة - إنها دائما مجال مثيل لفئة. لذلك using()
في كثير من الأحيان لا ينطبق.
إذا كان لديك حقل مثيل فئة هو مثيل ManualResetEvent
, ، جعل فصولك التنفيذ IDisposable
وفيك Dispose()
طريقة الاتصال ManualResetEvent.Close()
. وبعد ثم في جميع تفضيلات الفصل الخاص بك، تحتاج إلى استخدام using()
أو جعل تنفيذ الفئة المحتوية IDisposable
وكرر، وكرر ...
إذا كنت تستخدم ManualResetEvent
مع طرق مجهولة، من الواضح أنها مفيدة. ولكن كما ذكر SAM أنه يمكن تمريرها في كثير من الأحيان إلى العمال، ثم اضبط وأغلقت.
لذلك أود أن أقول ذلك يعتمد على سياق كيف تستخدمه - msdn waithandle.waitall () نموذج الكود لديه مثال جيد على ما أعنيه.
إليك مثال بناء على عينة MSDN من كيفية إنشاء WATHATHALS مع using
البيان استثناء:
system.objectdispusesception.
"تم إغلاق مقبض آمن"
const int threads = 25;
void ManualWaitHandle()
{
ManualResetEvent[] manualEvents = new ManualResetEvent[threads];
for (int i = 0; i < threads; i++)
{
using (ManualResetEvent manualResetEvent = new ManualResetEvent(false))
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ManualWaitHandleThread), new FileState("filename", manualResetEvent));
manualEvents[i] = manualResetEvent;
}
}
WaitHandle.WaitAll(manualEvents);
}
void ManualWaitHandleThread(object state)
{
FileState filestate = (FileState) state;
Thread.Sleep(100);
filestate.ManualEvent.Set();
}
class FileState
{
public string Filename { get;set; }
public ManualResetEvent ManualEvent { get; set; }
public FileState(string fileName, ManualResetEvent manualEvent)
{
Filename = fileName;
ManualEvent = manualEvent;
}
}