简体   繁体   中英

What is the correct way to pass data to a running thread

In most cases when you create your thread you can prepare the data beforehand and pass it into the constructor or method.

However in cases like an open socket connection you will typically already have a thread created but wish to tell it to perform some action.

Basic idea:

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?

So what is the correct way to pass data to a running thread in C# and Java?

Java

You could basically have a LinkedList (a LIFO ) and proceed (with something) like this (untested) :

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

As you keep a reference to the instance of the LinkedList given in argument, somewhere else, all you have to do is :

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

One way to pass data to a running thread is by implementing Message Queues . The thread that wants to tell the listening thread to do something would add an item to the queue of the listening thread. The listening thread reads from this thread in a blocking fashion. Causing it to wait when there are no actions to perform. Whenever another thread puts a message in the queue it will fetch the message, depending on the item and it's content you can then do something with it.

This is some Java / pseudo code:

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)
      {
        ...
      }
   }
}

And the caller:

class Caller
{
  private Listener listener;

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

Of course, there are a lot of best practices when programming paralllel/concurrent code. For example, instead of while(true) you should at the least add a field like run :: Bool that you can set to false when you receive a StopMessage. Depending on the language in which you want to implement this you will have other primitives and behaviour to deal with.

In Java for example you might want to use the java.util.Concurrent package to keep things simple for you.

Edit : Misread question,

C# What I normally do is create a Global Static Class and then set the values there. That way you can access it from both threads. Not sure if this is the preferred method and there could be cases where locking occurs (correct me if I'm wrong) which should be handled.

I haven't tried it but It should work for for the threadpool/backgroundworker as well.

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

Well, it depends a lot on the work that the thread is supposed to do. For example, you can have a thread waiting for a Event (eg ManualResetEvent) and a shared queue where you put work items (can be data structures to be processed, or more clever commands following a Command pattern). Somebody adds new work to the queue ad signals the event, so the trhread awakes, gets work from the queue and start performing its task.

You can encapsulate this code inside a custom queue, where any thread that calls the Deque methods stops until somebody calls Add(item).

On the other hand, maybe you want to rely on .NET ThreadPool class to issue tasks to execute by the threads on the pool.

Does this example help a bit?

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

You could run your worker thread within a loop (if that makes sense for your requirement) and check a flag on each execution of the loop. The flag would be set by the other thread to signal the worker thread that some state had changed, it could also set a field at the same time to pass the new state.

Additionally, you could use monitor.wait and monitor.pulse to signal the state changes between the threads.

Obviously, the above would need synchronization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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