【问题标题】:What is the correct way to pass data to a running thread将数据传递给正在运行的线程的正确方法是什么
【发布时间】:2011-04-12 14:25:17
【问题描述】:

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

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

基本思路:

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 c# multithreading events


    【解决方案1】:

    将数据传递给正在运行的线程的一种方法是实现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());
      }
    }
    

    当然,在编写并行/并发代码时有很多最佳实践。例如,您至少应该添加一个像run :: Bool 这样的字段,而不是while(true),当您收到StopMessage 时您可以将其设置为false。根据您要实现的语言,您将需要处理其他原语和行为。

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

    【讨论】:

      【解决方案2】:

      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 因为 oop 引用概念的很好的示例争论。因为引用是同一个对象。如果只从线程中的队列中读取,我猜队列状态会保持良好。
      • 重新阅读我的示例时,我可以封装LinkedList 并让方法完成整个同步(例如:pushNotificationonNotification 是一个抽象方法...)
      【解决方案3】:

      编辑:误读问题,

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

      我还没有尝试过,但它也应该适用于线程池/后台工作人员。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          嗯,这在很大程度上取决于线程应该完成的工作。 例如,您可以有一个等待事件的线程(例如 ManualResetEvent)和一个共享队列,您可以在其中放置工作项(可以是要处理的数据结构,或者遵循命令模式的更聪明的命令)。有人在队列中添加了新的工作,向事件发出信号,因此线程被唤醒,从队列中获取工作并开始执行其任务。

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

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

          这个例子有帮助吗?

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              【解决方案7】:

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

              此外,您可以使用 monitor.wait 和 monitor.pulse 来表示线程之间的状态变化。

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-12-16
                • 2011-09-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-04-05
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多