繁体   English   中英

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

[英]What is the correct way to pass data to a running thread

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

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

基本思路:

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中正在运行的线程的正确方法是什么?

Java的

您基本上可以拥有一个LinkedListLIFO )并进行如下操作(未经测试):

 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();
 }

将数据传递给正在运行的线程的一种方法是实现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)您至少应添加一个run :: Bool之类的字段,在收到StopMessage时可以将其设置为false。 根据您要实现该语言的语言,您将需要处理其他原语和行为。

例如,在Java中,您可能想使用java.util.Concurrent包来简化您的工作。

编辑 :误读的问题,

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

我还没有尝试过,但它也适用于线程池/ backgroundworker。

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

好吧,这很大程度上取决于线程应该执行的工作。 例如,您可以让一个线程等待一个事件(例如,ManualResetEvent),并在一个共享队列中放置工作项(可以是要处理的数据结构,或者是遵循命令模式的更巧妙的命令)。 有人将新工作添加到队列中,广告会在事件发生时发出信号,从而使信号唤醒,从队列中获取工作并开始执行其任务。

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

另一方面,也许您想依靠.NET ThreadPool类来发出要由池中的线程执行的任务。

这个例子有帮助吗?

您可以使用委托模式,其中子线程订阅事件,而主线程通过传递参数引发事件。

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

此外,您可以使用monitor.wait和monitor.pulse发出信号,告知线程之间的状态变化。

显然,以上将需要同步。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM