Поточная обработка C# выходит с AutoResetEvent

Другой метод должен поместить png позади UILabel. У меня есть представления с несколькими маркировками, которые накладывают единственный фон png, который имеет все иллюстрации для отдельных маркировок.

6
задан SwDevMan81 13 July 2011 в 16:24
поделиться

3 ответа

Это не проверено, но это элегантный способ сделать это с примитивами на основе .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; 
             }
     }
}
5
ответ дан 16 December 2019 в 21:44
поделиться

Здесь есть два возможных тревожных сценария.

1:

  • DoLongOperationWith_d (d) завершается.
  • Вызывается SetData (), сохраняющее новое значение в d.
  • Вызывается e.WaitOne (), но поскольку значение уже установлено, поток ждет вечно.

Если это вас беспокоит, я думаю, вы можете расслабиться. Из документации мы видим, что

Если поток вызывает WaitOne, когда AutoResetEvent находится в сигнальном состоянии, поток не блокируется. AutoResetEvent немедленно освобождает поток и возвращается в несигнальное состояние.

Так что это не проблема. Однако, в зависимости от того, как и когда вызывается SetData (), вы можете иметь дело с более серьезным

2:

  • SetData () вызывается, сохраняя новое значение в d и пробуждая бегуна.
  • DoLongOperationWith_d (d) запускается.
  • SetData () вызывается снова, сохранение нового значения в d.
  • SetData () вызывается снова! Старое значение d потеряно навсегда; DoLongOperationWith_d () никогда не будет вызван для него.

Если это ваша проблема, простейший способ ее решения - создание параллельной очереди. Реализаций предостаточно.

2
ответ дан 16 December 2019 в 21:44
поделиться

Вы можете использовать 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 . Я думаю, однако, вы должны исследовать ThreadPool.QueueUserWorkItem .

1
ответ дан 16 December 2019 в 21:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: