قائمة انتظار خالية من قفل الخيط الآمن - تحتاج المشورة

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

سؤال

أحتاج إلى تصميم مسجل آمن للخيط. يجب أن يكون مسجلي أسلوب سجل () يقوم ببساطة بنقل النص الذي سيتم تسجيله. أيضا يجب أن يكون مسجل خاليا من القفل - بحيث يمكن لمؤشر الترابط الآخر تسجيل الرسائل دون قفل المسجل. أحتاج إلى تصميم مؤشر ترابط عامل يجب أن ينتظر بعض حدث المزامنة ثم قم بتسجيل جميع الرسائل من قائمة الانتظار باستخدام تسجيل .NET قياسي (لا توجد مؤشر ترابط آمن). إذن ما أنا مهتم به هو مزامنة موضوع العمال - وظيفة السجل. أدناه هو رسم الطبقة التي صممتها. أعتقد أنني يجب أن تستخدم الشاشة. انتظر / نبض هنا أو أي وسيلة أخرى لتعليق وتستأنف موضوع العمال. لا أريد أن أقضي دورات وحدة المعالجة المركزية عندما لا توجد وظيفة للمسجل.

اسمحوا لي أن أضعها بطريقة أخرى - أريد تصميم مسجل سوف لا كتلة خيوط المتصل التي تستخدمها. لدي نظام عالية الأداء - وهذا هو شرط.

class MyLogger
{
  // This is a lockfree queue - threads can directly enqueue and dequeue
  private LockFreeQueue<String> _logQueue;
  // worker thread
  Thread _workerThread;
  bool _IsRunning = true;

 // this function is used by other threads to queue log messages
  public void Log(String text)
{
  _logQueue.Enqueue(text);
}

// this is worker thread function
private void ThreadRoutine()
{
 while(IsRunning)
 {
   // do something here
 }
}    
}
هل كانت مفيدة؟

المحلول

"خال من القفل" لا يعني أن المواضيع لن تمنع بعضها البعض. وهذا يعني أنهم يمنعون بعضهم البعض من خلال آليات فعالة للغاية ولكن أيضا آليات صعبة للغاية. مطلوب فقط لسيناريوهات عالية الأداء وحتى الخبراء يخطئون (كثيرا).

أفضل النصائح: ننسى "قفل خالية" واستخدام قائمة انتظار "آمنة للخيط".

أود أن أوصي "حظر قائمة انتظار" من هذه الصفحة.

وهي مسألة اختيار لتشمل ThreadRoutine (المستهلك) في الفصل نفسه.

إلى الجزء الثاني من سؤالك، يعتمد ذلك على ما هو "حدث هذا المزامنة" بالضبط. إذا كنت ستستخدم مكالمة طريقة، فدع ذلك يبدأ مؤشر ترابط واحد. إذا كنت ترغب في الانتظار على إشارة من لا استخدام الشاشة والنبض. انهم غير موثوق هنا. استخدم Autoresetevent / ManualResetevent.
كيفية السطح الذي يعتمد على الطريقة التي تريد استخدامها.

يجب أن تبدو مكوناتك الأساسية مثل هذا:

class Logger
{
    private AutoResetEvent _waitEvent = new AutoResetEvent(false);
    private object _locker = new object();
    private bool _isRunning = true;    

    public void Log(string msg)
    {
       lock(_locker) { _queue.Enqueue(msg); }
    }

    public void FlushQueue()
    {
        _waitEvent.Set();
    }

    private void WorkerProc(object state)
    {
        while (_isRunning)
        {
            _waitEvent.WaitOne();
            // process queue, 
            // ***
            while(true)
            {
                string s = null;
                lock(_locker)
                {
                   if (_queue.IsEmpty) 
                      break;
                   s = _queue.Dequeu();
                }
                if (s != null)
                  // process s
            }
        } 
    }
}

يبدو أن جزءا من المناقشة هو ما يجب القيام به عند معالجة قائمة الانتظار (ملحوظ ***). يمكنك قفل قائمة الانتظار ومعالجة جميع العناصر، سيتم حظر جميع العناصر، والتي يتم خلالها حظر إضافة الإدخالات الجديدة (أطول) أو قفل وإدخال الإدخالات واحدا تلو الآخر وقفل فقط (جدا) في كل مرة. لقد عدت هذا السيناريو الأخير.

ملخص: أنت لا تريد حل خال من القفل ولكن خالية من الكتلة. خالية من الكتلة غير موجودة، سيتعين عليك الاستقرار لشيء ما يمنع بأقل قدر ممكن. يظهر التكرار الأخير لعينة Mys (Incomplete) كيفية قفل فقط حول المكالمات النكزية و Dequeue. أعتقد أن هذا سيكون بسرعة كافية.

نصائح أخرى

هل أظهرت لك ملف التعريف الخاص بك أنك تعاني من مرفقات كبيرة باستخدام بسيطة lock بيان؟ من الصعب للغاية الحصول على البرمجة الخالية من القفل، وإذا كنت بحاجة فعلا، أود أن أقترح شيئا موجودا من مصدر موثوق.

ليس من الصعب إجراء خال من القفل إذا كان لديك عمليات ذرية. اتخاذ قائمة مرتبطة منفردة؛ أنت فقط بحاجة إلى رئيس مؤشر.

وظيفة السجل:
1. تحضير محلي عنصر السجل (عقدة مع سلسلة تسجيل).
2. قم بتعيين مؤشر العقدة المحلي التالي رئيس.
3. الذري: يقارن رئيس مع العقدة المحلية المقبل، إذا متساو، استبدال رئيس مع عنوان العقدة المحلية.
4. إذا فشلت العملية، كرر من الخطوة 2، وإلا، فإن العنصر موجود في "قائمة الانتظار".

عامل:
1. نسخ رئيس محليا.
2. الذري: يقارن رئيس مع المحلي واحد، إذا قدم المساواة، واستبدال رئيس مع فارغة.
3. إذا فشلت العملية، كرر من الخطوة 1.
4. إذا نجحت، معالجة العناصر؛ وهي الآن محلية وخارج "قائمة الانتظار".

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