views:

210

answers:

6
+3  Q: 

Threading in c#

How to call a function which takes two parameters using threading in C#? I have to call StartDNIThread(string storeID, string queryObject) from another function.I have to pass the two values.Both are string

+8  A: 

Your options are:

  • Encapsulate the parameters in a new class, and put the method to use for the delegate into that class.
  • Use anonymous functions (anonymous methods or lambda expressions) to do the same thing automatically with captured variables.

The latter is generally easier of course. You haven't shown what you're doing with the thread, but you might do something like:

string storeID = "...";
string queryObject = "...";

Thread t = new Thread(() => StartDNIThread(storeID, queryObject));
t.Start();

Note that because the variables are captured, you shouldn't change the values until after you know the thread has actually started. You can work around this by using captured variables only used by the anonymous function:

string storeID = "...";
string queryObject = "...";

string storeIDCopy = storeID;
string queryObjectCopy = queryObject;
Thread t = new Thread(() => StartDNIThread(storeIDCopy, queryObjectCopy));
t.Start();
// You can now change storeID and queryObject freely

This is particularly important if you're doing anything in a loop, as the loop variables themselves will change. For example:

foreach (string storeID in stores)
{
    string storeIDCopy = storeID;
    Thread t = new Thread(() => StartDNIThread(storeIDCopy, queryObject));
    t.Start();
}

If you're using the thread pool or any other way of starting threads, the pattern is basically the same.

Jon Skeet
Upvote for lambdas.
Rap
+2  A: 

Using the threadpool:

string str1 = "str1";
string str2 = "str2";
ThreadPool.QueueUserWorkItem(state =>
                            {
                               Console.WriteLine("{0}:{1}", str1, str2);
                            });

If you want to do some alternate-thread processing involving a UI, you're best using the BackgroundWorker.

Neil Barnwell
+5  A: 
ThreadStart threadStart = delegate{StartDNIThread(string storeID, string queryObject);};
Thread thread = new Thread(threadStart);
thread.Start();

Or with lambdas:

ThreadStart threadStart = () => StartDNIThread(string storeID, string queryObject);
Thread thread = new Thread(threadStart);
thread.Start();
Charlie
I am getting the following errorAn unhandled exception of type 'System.NullReferenceException' occurred in App_Code.g2edzdox.dllAdditional information: Object reference not set to an instance of an object.
JJ
+1  A: 

There is a ParameterizedThreadStart delegate which you could use. This delegate requires a method which takes one argument (of tyoe object). So, in fact you could use a custom type (class or struct) which contains the 2 variables that you want to pass to the ParameterizedThreadStart.

Like this:

Thread t = new Thread (new ParameterizedThreadStart (DoWork));
t.Start(new MyType(storeId, queryObject));

But, in such situations, I prefer to do it in another way. I prefer to create a custom 'Task' type, which abstracts all of these things. Like this:

public class Task
{

     private readonly int _storeId;
     private readonly string _queryObject;

     public Task(int storeId, string queryObject)
     {
         _storeId = storeId;
         _queryObject = queryObject;
     }

     public void Start()
     {
         Thread t = new Thread (new ThreadStart(DoWork));
         t.Start();
     }

     private void DoWork()
     {
         // Do your thing here.
     }

}
Frederik Gheysels
A: 

I tend to create a task object something like the following

class myClass
{
    public void CallingCode()
    {
        ProcessRequest pr1 = new ProcessRequest("storeD","queryObj");
        ThreadStart ts1 = new ThreadStart(pr1.Go);
        Thread wrk = new Thread(ts1);
        wrk.Start();
    }
}


class ProcessRequest
{
    private string storeD;
    private string queryObj;

    public ProcessRequest(string storeD, string queryObj)
    {
        this.stroreD = storeD;
        this.queryObj = queryObj;
    }

    public void Go()
    {
        try
        {//your processing code here you can access $this->storeD and $this->queryObj

        }
        catch (Exception ex)
        {

        }
    }
}
You must likely want to add some events to that to see when the procssing had finished, depends what you are doing really though.i.e in ProcessRequestpublic delegate void ProcessFinished(ProcessRequest req);public event ProcessFinished EFinished;at the end of your Go() method:if (this.EFinished != null) EFinished(this);This way you can process if need be the finish event:pr1.EFinished += new ProcessRequest.ProcessFinished(pr1_EFinished);void pr1_EFinished(ProcessRequest req) { }I guess there are many ways to skin this cat though.
A: 

I personally like the delegate route:

private delegate void StartDNIThreadDelegate(string storeID, string queryObject);

private static void Main()
{
    string storeID = "...";
    string queryObject = "...";
    StartDNIThreadDelegate startDNIThread = new StartDNIThreadDelegate(StartDNIThread);
    IAsyncResult result = startDNIThread.BeginInvoke(storeID, queryObject, new AsyncCallback(StartDNIThreadDone), startDNIThread);

    // Do non-threaded stuff...

    result.AsyncWaitHandle.WaitOne(); // wait for thread to finish.
}

private static void StartDNIThread(string storeID, string queryObject)
{
    // Do StartDNIThreading stuff.
}

private static void StartDNIThreadDone(IAsyncResult result)
{
    StartDNIThreadDelegate startDNIThread = (StartDNIThreadDelegate)result.AsyncState;

    // Do after thread finished cleanup.

    startDNIThread.EndInvoke(result);
}
Jesse C. Slicer