views:

207

answers:

5

I've got a method that gets called on an event, which presents me with two variables varA, varB (both strings). This method gets called with new information quite frequently, thus I have created a separate method that takes in the two parameters. I want to run this method in a thread, however have struck the issue that Thread.Start will not accept parameters.

I've tried a few supposed methods, but have so far had no luck.. I think my best bet is to create a separate class, and handle it there.. However I have a List which I am inserting data into, and hit a dead end when the separate class tried to access that list, since it was in a different class.

Can someone help me out here please?

+2  A: 

The start method of thread accepts an object parameter.

If your method accepts multiple parameters, then you can very well pass an object of your class containing the parameters into it. You can then unbox it in your method.

Thread.Start(Object)

http://msdn.microsoft.com/en-us/library/system.threading.thread.start.aspx

Update

In your case, try this,

string varC = varA + "," + varB;
Thread.Start(varC);

and in your method

string args[] = ((string)par).Split(',');
Veer
I saw that, but I couldn't figure out how to turn the object back into an array..
Matt
sorry, in that case you'll need to wrap your parameters in a class and pass an instance. Anyways since you're just using only two string variable, you can better concatenate and split them when required.
Veer
got it going.. well got it compiling without issues :p Thanks
Matt
Glad it helped you. Cheers!!!
Veer
As i said **in your case** since you're using only two string variables, you can take up this solution. But you can better put them in an array and unbox it in your method like this: > string args[] = par as string[]; or > Array args = par as Array;
Veer
A: 

Hello, you can execute method with parameters in another thread in different ways: via Thread class, via System.ComponentModel.BackgroundWorker, via ThreadPool. If method gets called frequently, i think ThreadPool ll fit:

        ThreadPool.QueueUserWorkItem(
        (args)=>
            {
                try
                {
                //args - object, you can put in it string[] or
                // whatever you want

                // do work
                }
                catch(Exception e)
                {
                    // dont throw exceptions in this thread
                    // or application will crashed
                }
            }
        );

You can read about this classes on msdn:

http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx

http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Andrew
A: 

Instead of using System.Thread, you could use a delegate.

e.g.:

public delegate void RunMyMethod(String a, String b);

RunMyMethod myDelegate = new RunMyMethod(MyMethod);
myDelegate.BeginInvoke(someAFromSomeWhere, someBFromSomeWhere);

Where MyMethod is the method you want to run, and the parameters are pulled from wherever necessary.

ck
+3  A: 

A simple solution...
This will print varA, varB to the console.

new RunTask<string, string>("varA", "varB").StartThread();

public class RunTask<TA, TB>
{
    public TA VarA { get; private set; }
    public TB VarB { get; private set; }

    public RunTask(TA varA, TB varB)
    {
        VarA = varA;
        VarB = varB;
    }
    public void StartThread()
    {
        ThreadPool.QueueUserWorkItem(Worker, this);
    }
    public void Worker(object obj)
    {
        var state = obj as RunTask<TA,TB>;
        Console.WriteLine(state.VarA + ", " + state.VarB);
    }
}

Edit:
If you want a solution where you need to update the UI this is probably a better solution.
And it is probably a better solution to put the arguments in a separate class like this.
Insert code to update list after the comment // Update List

public class ListForm : Form
{
    private static readonly object _listResultLock = new object();
    private readonly Action<TaskResult> _listResultHandler;

    public ListForm()
    {
        Load += ListForm_Load;
        _listResultHandler = TaskResultHandler;
    }

    private void ListForm_Load(object sender, EventArgs e)
    {
        new RunTask(new Task("varA", "varB", TaskResultHandler)).StartThread();
    }
    public void TaskResultHandler(TaskResult result)
    {
        if (InvokeRequired)
        {
            Invoke(_listResultHandler, result);
            return;
        }
        lock (_listResultLock)
        {
            // Update List
        }
    }
}

public class Task
{
    public Action<TaskResult> Changed { get; private set; }
    public string VarA { get; private set; }
    public string VarB { get; private set; }

    public Task(string varA, string varB, Action<TaskResult> changed)
    {
        VarA = varA;
        VarB = varB;
        Changed = changed;
    }
}
public class TaskResult
{
    public string VarA { get; private set; }
    public string VarB { get; private set; }

    public TaskResult(string varA, string varB)
    {
        VarA = varA;
        VarB = varB;
    }
}
public class RunTask
{
    private readonly Task _task;

    public RunTask(Task task)
    {
        _task = task;
    }
    public void StartThread()
    {
        ThreadPool.QueueUserWorkItem(Worker, _task);
    }
    public void Worker(object obj)
    {
        var state = obj as Task;
        if (state == null) return;
        if (state.Changed == null) return;
        state.Changed(new TaskResult("this is " + state.VarA, "this is " + state.VarA));
    }
}
Jens Granlund
+1 , this is the method I use
SLC
The issue I rant into with this method was that I need to access and update a List that exists in the main class. When I tried to use it as a parameter also, I kept getting issues regarding inconsistent accessibility regarding classes
Matt
You could pass a reference to the parent, and make sure you use a Lock to make it threadsafe, or you could make a static reference to your parent in your program launch code. If your List is being dynamically updated from threads, it might make sense to move it out of the main class anyway.
SLC
Updated with an alternative solution to handle UI updates.
Jens Granlund
+1  A: 

If you know what will be supplied to the thread, then you may want to pass objects to it.

Read more here -> http://msdn.microsoft.com/en-us/library/6x4c42hc.aspx

Example:

void someFunction()
{
    Thread t = new Thread(doWork);

Then,

    t.Start(new int[] { 1, 2 }); //two values passed to the thread.

Or,

    t.Start(1); //one value passed to the thread.
}



Now, the method -

void doWork(object data)
{
    System.Collections.IList list = data as System.Collections.IList;
    if (list != null)
    {
        object[] _objArr = data as object[];
        foreach (object io in list)
        {
            System.Diagnostics.Trace.WriteLine(io);
        }
    }
    else
    {
        System.Diagnostics.Trace.WriteLine(data);
    }
}
Nayan
+1 for the as operator
Veer