views:

478

answers:

3

Can i make any function like

public void myfunc()
{
   //some processing
}

a thread function by

Thread t = new Thread (new ThreadStart (myfunc));

then some where

t.Start();

and can i pass any type of arguments to that?

+6  A: 

In theory you can make any method execute in a separate thread, as long as you follow some rules (e.g. synchronization, invoke delegates to update ui, etc.).

From your question I understand that you do not have much experience with multi threaded programming, so I advise you to read a lot about threading and learn about the dangers and problems that can arise. You may also use the background worker class that take some of the responsibilities from you.

Also, yes, you can pass parameters to a thread method:

private class ThreadParameters
{
   ....
}

...

public void ThreadFunc(object state)
{
    ThreadParameters params = (ThreadParameters)state;
    ....
}

Thread t = new Thread(new ParameterizedThreadStart(ThreadFunc));
t.Start(new ThreadParameters() { ... });
Thorsten Dittmar
+5  A: 

There is an overload that accepts an object state - however, IMO the easiest way to pass arbitrary arguments to a threadstart (and verify the signature at compile time) is with an anonymous method:

int a = ...
string b = ...
Thread t = new Thread (delegate() { SomeFunction(a,b);});

Just (and this is important) - *don't change a or b after this, as the change will be reflected to the thread (as a race) - i.e. don't do:

int a = ...
string b = ...
Thread t = new Thread (delegate() { SomeFunction(a,b);});
a = 12; // this change will be visible to the anonymous method - be careful ;-p

In the case of loops, it is important (when dealing with async and captured variables) to introduce extra variables for this; these are very different

    int[] data = {1,2,3,4,5};
    foreach(int i in data) {
        ThreadPool.QueueUserWorkItem(delegate {
            Console.WriteLine(i); });
    }
    Console.ReadLine();

(which will probably print 5,5,5,5,5)

    int[] data = {1,2,3,4,5};
    foreach (int i in data) {
        int tmp = i;
        ThreadPool.QueueUserWorkItem(delegate {
            Console.WriteLine(tmp); });
    }
    Console.ReadLine();

(which will print 1-5 in no particular order)


Update to discuss Meeh's point (comments); what does this print (99.999% of the time - there is a race condition)?

    string s = "dreams";
    ThreadPool.QueueUserWorkItem(delegate {
        Console.WriteLine(s);
    });
    s = "reality";
    Console.ReadLine();
Marc Gravell
You can avoid the cast if you tell it explicitly that the delegate has no parameters, ie new Thread (delegate() { SomeFunction(a,b);})
KeeperOfTheSoul
Tidied, cheers.
Marc Gravell
Erm, aren't int an value-type and hence, being passed-by-value? Changing a after the thread has been created will not change the value the thread received, or am I wrong? Same thing goes for the string, though it's a reference type - So all you'd change would be the local scopes b-handle target. Using SomeFunction(ref a, ref b) would do what you said.. I'm not quite sure though, I ussually check stuff like this briefly on the fly :)
cwap
I'll add an update just to show this... (at the bottom)
Marc Gravell
(and it doesn't matter that string is a reference type; it is immutable - this isn't related to ref-type/value-type)
Marc Gravell
Oopsie, didn't notice that you used the object initializer C# syntax. You are very right in your statement, and I'm very wrong :) ref/vvalue types doesn't have anything to do with this as you guys said ..
cwap
The problem is that `s` is really a field on a compiler-generated instance; updates are visible to anything that shares the capture-context.
Marc Gravell
Er... I haven't used any object initializer syntax...
Marc Gravell
I'm tired.. Stupid carpenter been noisy all morning. Sorry about that - I get your examples, just can't seem to type the right thing atm :)
cwap