سؤال

كيفية مزامنة هذا بشكل صحيح؟ في الوقت الحالي، من الممكن ذلك SetData يسمى بعد ذلك e.WaitOne() أكمل ذلك d يمكن تعيينها بالفعل إلى قيمة أخرى. حاولت إدراج أقفال لكنها أسفرت عن طريق مسدود.

AutoResetEvent e = new AutoResetEvent(false);

public SetData(MyData d)
{
   this.d=d;
   e.Set();    // notify that new data is available
}

// This runs in separate thread and waits for d to be set to a new value
void Runner() 
{    
   while (true)
   {
      e.WaitOne();  // waits for new data to process
      DoLongOperationWith_d(d);
   }
}

هل سيكون أفضل حل تقديم متغير منطقي جديد dataAlreadyBeenSetAndWaitingToBeProcessed التي تم تعيينها في SetData إلى صحيح وفي نهاية DoLongOperationWith_d يمكن ضبطها على TRUE، لذلك إذا SetData يسمى مع هذا المتغير المحدد إلى صحيح يمكن أن يعود فقط؟

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

المحلول

هذا غير مختبر، ولكن طريقة أنيقة للقيام بذلك مع البدائيات .NET القائمة:

class Processor<T> {
    Action<T> action;
    Queue<T> queue = new Queue<T>();

    public Processor(Action<T> action) {
        this.action = action;
        new Thread(new ThreadStart(ThreadProc)).Start();
    }

    public void Queue(T data) {
        lock (queue) {
            queue.Enqueue(data);
            Monitor.Pulse(queue); 
        }            
    }

    void ThreadProc() {
        Monitor.Enter(queue);
        Queue<T> copy;

        while (true) {                 
            if (queue.Count == 0) {
                Monitor.Wait(queue);
            }

            copy = new Queue<T>(queue);
            queue.Clear();
            Monitor.Exit(queue);

            foreach (var item in copy) {
                action(item); 
            }

            Monitor.Enter(queue); 
        }
    }
}

مثال البرنامج:

class Program {

    static void Main(string[] args) {

        Processor<int> p = new Processor<int>((data) => { Console.WriteLine(data);  });
        p.Queue(1);
        p.Queue(2); 

        Console.Read();

        p.Queue(3);
    }
}

هذه نسخة غير قائمة الانتظار، قد يفضل إصدار قائمة الانتظار:

object sync = new object(); 
AutoResetEvent e = new AutoResetEvent(false);
bool pending = false; 

public SetData(MyData d)
{
   lock(sync) 
   {
      if (pending) throw(new CanNotSetDataException()); 

      this.d=d;
      pending = true;
   }

   e.Set();    // notify that new data is available
}

void Runner() // this runs in separate thread and waits for d to be set to a new value
{

     while (true)
     {

             e.WaitOne();  // waits for new data to process
             DoLongOperationWith_d(d);
             lock(sync) 
             {
                pending = false; 
             }
     }
}

نصائح أخرى

هناك سيناريوهات مقلقة من المحتمل هنا.

1:

  • dolongoperationwith_d (د) التشطيبات.
  • يسمى SetData ()، تخزين قيمة جديدة في د.
  • يسمى E.waitone ()، ولكن نظرا لأن القيمة قد تم بالفعل تعيين الخيط ينتظر إلى الأبد.

إذا كان هذا اهتمامك، أعتقد أنه يمكنك الاسترخاء. من توثيق, ، نحن نرى ذلك

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

لذلك هذه ليست مشكلة. ومع ذلك، اعتمادا على كيفية ومتى يسمى SetData ()، قد تكون تتعامل مع أكثر خطورة

2:

  • يسمى SETDATA ()، تخزين قيمة جديدة في D ويقوم بتنزيع العداء.
  • dolongoperationwith_d (د) يبدأ.
  • يسمى SetData () مرة أخرى، تخزين قيمة جديدة في د.
  • يسمى setdata () مرة أخرى! يتم فقد القيمة القديمة لل D إلى الأبد؛ لن يتم استدعاء dolongoperationwith_d () أبدا.

إذا كانت هذه مشكلتك، فإن أبسط طريقة لحلها هي قائمة انتظار متزامنة. تطبيقات كثيرة.

يمكنك استخدام 2 الأحداث،

AutoResetEvent e = new AutoResetEvent(false);
AutoResetEvent readyForMore = new AutoResetEvent(true); // Initially signaled

public SetData(MyData d)
{
   // This will immediately determine if readyForMore is set or not.
   if( readyForMore.WaitOne(0,true) ) {
     this.d=d;
     e.Set();    // notify that new data is available
  }
  // you could return a bool or something to indicate it bailed.
}

void Runner() // this runs in separate thread and waits for d to be set to a new value
{

     while (true)
     {

             e.WaitOne();  // waits for new data to process
             DoLongOperationWith_d(d);
             readyForMore.Set();
     }
}

واحدة من الأشياء التي يمكنك القيام بها مع هذا النهج لديها setdata تأخذ المهلة، وتمرير ذلك WaitOne. وبعد أعتقد أن كنت shoudl التحقيق ThreadPool.QueueUserWorkItem.

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