将数据传递给正在运行的线程的正确方法是什么

时间:2011-04-12 14:25:18

标签: java c# multithreading events

在大多数情况下,当您创建线程时,您可以预先准备数据并将其传递给构造函数或方法。

然而,在开放套接字连接的情况下,您通常已经创建了一个线程,但希望告诉它执行某些操作。

基本理念:

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 个答案:

答案 0 :(得分:2)

<强>爪哇

你基本上可以有一个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 :(得分:2)

将数据传递到正在运行的线程的一种方法是实现Message Queues。想要告诉侦听线程做某事的线程会将一个项添加到侦听线程的队列中。侦听线程以阻塞方式从该线程读取。在没有要执行的操作时使其等待。每当另一个线程将消息放入队列时,它将获取消息,具体取决于项目及其内容,您可以使用它执行某些操作。

这是一些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) :: Bool之类的字段,而不是run,您可以在收到StopMessage时将其设置为false。根据您要实现此语言的语言,您将有其他原语和行为来处理。

在Java中,您可能希望使用java.util.Concurrent包来简化操作。

答案 2 :(得分:1)

修改:误读问题,

C# 我通常做的是创建一个全局静态类,然后在那里设置值。这样你就可以从两个线程访问它。不确定这是否是首选方法,并且可能存在锁定发生的情况(如果我错了,请纠正我)应该处理。

我还没有尝试过,但它也应该适用于threadpool / backgroundworker。

答案 3 :(得分:0)

我能想到的一种方法是通过属性文件。

答案 4 :(得分:0)

嗯,这很大程度上取决于线程应该做的工作。 例如,您可以让一个线程等待一个事件(例如ManualResetEvent)和一个共享队列,您可以在其中放置工作项(可以是要处理的数据结构,也可以是遵循Command模式的更聪明的命令)。有人在队列广告中添加新工作来表示事件,因此trhread唤醒,从队列中获取工作并开始执行其任务。

您可以将此代码封装在自定义队列中,其中调用Deque方法的任何线程都会停止,直到有人调用Add(item)。

另一方面,也许您希望依赖.NET ThreadPool类来发出由池上的线程执行的任务。

这个例子有用吗?

答案 5 :(得分:0)

你可以使用委托模式,其中子线程订阅一个事件,主线程引发一个事件,传递参数。

答案 6 :(得分:0)

您可以在循环中运行您的工作线程(如果这对您的要求有意义)并在每次执行循环时检查一个标志。该标志将由另一个线程设置,以向工作线程发出某个状态已更改的信号,它还可以同时设置一个字段以传递新状态。

此外,您可以使用monitor.wait和monitor.pulse来指示线程之间的状态更改。

显然,上述内容需要同步。