user1296153
user1296153

Reputation: 585

How to pass parameters to threads that have already started running

Hi I have an application that uses one thread to copy buffer from *src to *dst but I want to have the thread started at the beginning of the program. When I want to use the thread I want to pass *src, *dst and size to the thread so that it can start copying the buffer. How do I achieve this ? Because when I start a thread I pass the values as I instantiate the object, ThreadX when creating a thread.

Thread^ t0 = gcnew Thread(gcnew ThreadStart(gcnew ThreadX(output, input, size), &ThreadX::ThreadEntryPoint));

To summarize I want to do this way:

  1. program starts
  2. create a thread
  3. wait in the thread
  4. pass the parameters and wake up the thread to start copying
  5. once copying is done in the thread then let the main thread know it's done
  6. just before the program ends join the thread

The sample code is shown below.

Thanks!

#include "stdafx.h"
#include <iostream>
#if 1

using namespace System;
using namespace System::Diagnostics;
using namespace System::Runtime::InteropServices;
using namespace System::Threading;

public ref class ThreadX
{
    unsigned short* destination;
    unsigned short* source;
    unsigned int num;

public:
    ThreadX(unsigned short* dstPtr, unsigned short* srcPtr, unsigned int size)
    {
        destination = dstPtr;
        source = srcPtr;
        num = size;
    }

    void ThreadEntryPoint()
    {
        memcpy(destination, source, sizeof(unsigned short)*num);
    }

};


int main()
{

    int size = 5056 * 2960 * 10; //iris 15 size
    unsigned short* input; //16bit
    unsigned short* output;
    Stopwatch^ sw = gcnew Stopwatch();

    input = new unsigned short[size];
    output = new unsigned short[size];

    //elapsed time for each test
    int sw0;
    int sw1;
    int sw2; 
    int sw3;

    //initialize input
    for (int i = 0; i < size; i++) { input[i] = i % 0xffff; }

    //initialize output
    for (int i = 0; i < size; i++) { output[i] = 0; }


    // TEST 1 //////////////////////////////////////////////////////////////////////
    for (int i = 0; i < size; i++) { output[i] = 0; }

    //-----------------------------------------------------------------------
    Thread^ t0 = gcnew Thread(gcnew ThreadStart(gcnew ThreadX(output, input, size), &ThreadX::ThreadEntryPoint));
    t0->Name = "t1";
    t0->Start();
    t0->Join();
    //-----------------------------------------------------------------------


    return 0
}

Upvotes: 0

Views: 814

Answers (2)

nsuneja
nsuneja

Reputation: 336

Basically, you need some basic building blocks for solving this problem (I am assuming you want to perform this copy operation just once. We can easily extend the solution if you have a constant stream of inputs):

1) Shared memory - For exchanging control information. In this case, it would be source buffer pointer, destination buffer pointer and size (from main thread to worker thread). You would also want some datastructure (lets begin with a simple boolean flag) to share information in the reverse direction (from worker thread to main thread), when the work is done.

2) Conditional variable - To send signal from main thread to worker thread, and in reverse direction. So, you need 2 different conditional variables.

3) A synchronization primitive like a mutex to protect the shared memory (Since they would be simultaneously accessed by both threads)

Given these building blocks, the pseudo code of your program will look like this:

struct Control {
     void* src, *dest;
     int num_of_bytes = -1;
     bool isDone = false;
     conditional_var inputReceived;
     conditional_var copyDone;
     mutex m;
};

 void childThread() {
     m.lock();
     while (num_of_bytes == -1) {
         inputReceived.wait(m); // wait till you receive input.
     }
     // Input received. Make sure you set src and dest pointers, before setting num_of_bytes
     mempcy(dest, src, num_of_bytes);
     isDone = true; // mark work completion.
     copyDone.notify(); // notify the main thread of work completion.
     m.unlock();
}


void mainThread()
{
      // Create worker thread at start;
      thread_t thread = pthread_create(&childThread);

      // Do other stuff...
      //
      //

      // Input parameters received. Set control information, and notify the 
      //  workerthread.
      mutex.lock();
      src = input.src;
      dest = input.dest;
      num_of_bytes = input.num_of_bytes;

      inputReceived.notify(); // wake up worker thread.

      while (!isDone) { // Wait for copy to be over.
           copyDone.wait();
      }

      m.unlock();  // unlock the mutex.
      thread.join(); // wait for thread to join. If the thread has already ended before we execute thread join, it will return immediately.

}

If you want to extend this solution to handle a stream of inputs, we can use 2 queues for requests and responses, with each element of the queue being input and output parameters.

Upvotes: 1

David Yaw
David Yaw

Reputation: 27864

Don't suspend the thread. That's bad design, and is highly likely to cause you problems down the road.

Instead, think of it like this: Have the thread block waiting for information on what it should do. When it gets that information, it should unblock, do the work, then block again waiting for the next thing.

A quick search for "C# blocking collection" reveals the BlockingCollection<T> class, and this guide to cancelling one of the blocking operations. Make it so that you activate the CancellationToken when it's time for your thread to exit, and have the thread sit waiting at the blocking operation when it's not doing work.

Upvotes: 0

Related Questions