Как правильно передавать данные в работающий поток? - PullRequest
2 голосов
/ 12 апреля 2011

В большинстве случаев при создании потока вы можете заранее подготовить данные и передать их в конструктор или метод.

Однако в таких случаях, как соединение с открытым сокетом, вы, как правило, уже создали поток, но хотите сказать ему выполнить какое-то действие.

Основная идея:

C#

private Thread _MyThread = new Thread(MyMethod);
this._MyThread.Start(param);   

Java

private Thread _MyThread = new Thread(new MyRunnableClass(param));
this._MyThread.start();

Now what?

Итак, как правильно передавать данные в работающий поток в C # и Java?

Ответы [ 7 ]

2 голосов
/ 12 апреля 2011

Одним из способов передачи данных в работающий поток является реализация очереди сообщений .Поток, который хочет, чтобы прослушивающий поток что-то сделал, добавил бы элемент в очередь прослушивающего потока.Поток прослушивания читает из этого потока блокирующим образом.Вызывает ожидание, когда нет действий для выполнения.Всякий раз, когда другой поток помещает сообщение в очередь, он извлекает сообщение, в зависимости от элемента и его содержимого, тогда вы можете что-то с ним сделать.

Это некоторый код Java / псевдокод:

class Listener
{
   private Queue queue;
   public SendMessage(Message m)
   {
     // This will be executed in the calling thread.
     // The locking will be done either in this function or in the Add below
     // depending on your Queue implementation.
     synchronize(this.queue) 
     {
        this.queue.put(m);
     }
   }

   public Loop()
   {
     // This function should be called from the Listener thread.
     while(true) 
     {
        Message m = this.queue.take();
        doAction(m);
     }
   }

   public doAction(Message m)
   {
      if (m is StopMessage)
      {
        ...
      }
   }
}

И вызывающая сторона:

class Caller
{
  private Listener listener;

  LetItStop()
  {
     listener.SendMessage(new StopMessage());
  }
}

Конечно, существует много лучших практик при программировании параллельного / параллельного кода.Например, вместо while(true) вы должны по крайней мере добавить поле типа run :: Bool, которое вы можете установить в false при получении StopMessage.В зависимости от языка, на котором вы хотите реализовать это, у вас будут другие примитивы и поведение для работы.

Например, в Java вы можете использовать пакет java.util.Concurrent для сохранениявсе просто для тебя.

2 голосов
/ 12 апреля 2011

Java

Вы могли бы в основном иметь LinkedList ( LIFO ) и продолжить (с чем-то), как это (не проверено):

 class MyRunnable<T> implements Runnable {
     private LinkedList<T> queue;
     private boolean stopped;
     public MyRunnable(LinkedList<T> queue) { 
         this.queue = queue; 
         this.stopped = false; 
     }
     public void stopRunning() {
         stopped = true;
         synchronized (queue) {
             queue.notifyAll();
         }
     }
     public void run() {
         T current;
         while (!stopped) {
             synchronized (queue) {
                 queue.wait();
             }
             if (queue.isEmpty()) {
                 try { Thread.sleep(1); } catch (InterruptedException e) {}
             } else {
                 current = queue.removeFirst();

                 // do something with the data from the queue

             }
             Thread.yield();
         }
     }
 }

Когда вы сохраняете ссылку на экземпляр LinkedList, указанный в аргументе, где-то еще, все, что вам нужно сделать, это:

 synchronized (queue) {
    queue.addLast(T);  // add your T element here. You could even handle some
                       // sort of priority queue by adding at a given index
    queue.notifyAll();
 }
1 голос
/ 12 апреля 2011

Редактировать : неправильно прочитанный вопрос,

C # Обычно я создаю глобальный статический класс, а затем устанавливаю там значения. Таким образом, вы можете получить к нему доступ из обоих потоков. Не уверен, что это предпочтительный метод, и могут быть случаи блокировки (поправьте меня, если я ошибаюсь), которые должны быть обработаны.

Я не пробовал, но это должно работать и для пула потоков / фонового работника.

0 голосов
/ 12 апреля 2011

Вы можете запустить свой рабочий поток в цикле (если это имеет смысл для вашего требования) и проверять флаг при каждом выполнении цикла. Этот флаг будет установлен другим потоком, чтобы сигнализировать рабочему потоку, что какое-то состояние изменилось, он также может одновременно установить поле для передачи нового состояния.

Кроме того, вы можете использовать monitor.wait и monitor.pulse, чтобы сигнализировать об изменении состояния между потоками.

Очевидно, что для вышеуказанного потребуется синхронизация.

0 голосов
/ 12 апреля 2011

Можно использовать шаблон делегата, когда дочерние потоки подписываются на событие, а основной поток вызывает событие, передавая параметры.

0 голосов
/ 12 апреля 2011

Ну, это во многом зависит от работы, которую должен выполнять поток.Например, у вас может быть поток, ожидающий событие (например, ManualResetEvent), и общая очередь, в которую вы помещаете рабочие элементы (это могут быть структуры данных для обработки или более умные команды, следующие шаблону команд).Кто-то добавляет новую работу в очередь, и он сигнализирует о событии, поэтому trhread просыпается, получает работу из очереди и начинает выполнять свою задачу.

Вы можете инкапсулировать этот код в пользовательскую очередь, где любой поток, вызывающийМетоды deque останавливаются до тех пор, пока кто-нибудь не вызовет Add (item).

С другой стороны, возможно, вы захотите использовать класс .NET ThreadPool для выдачи задач, выполняемых потоками в пуле.

Этот пример немного помогает?

0 голосов
/ 12 апреля 2011

Я могу думать только о файлах свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...