Reputation: 34770
use ThreadPool.QueueUserWorkItem (WaitCallback, Object)
to start a thread with my target method and data. Can I pass more than one data into my method? the second parameter in QueueUserWorkItem (WaitCallback, Object)
can be an array?
Upvotes: 5
Views: 5655
Reputation: 127573
Here is a example of using a class so you can get strongly typed pramaters
public class CreateUserTaskInfo
{
public string username { get; };
public string password { get; };
public string sqlServer { get; };
public string database { get; };
public string practice { get; };
public RemoteUserManager client { get; };
public CreateUserTaskInfo(RemoteUserManager cli, string usr, string pass, string sql, string db, string prac)
{
client = cli;
username = usr;
password = pass;
sqlServer = sql;
database = db;
practice = prac;
}
}
public void ExampleFunction(...)
{
//gather up the variables to be passed in
var taskInfo = new CreateUserTaskInfo(remote, user, password, SqlInstancePath, AccountID, practiceName);
//queue the background work and pass in the state object.
ThreadPool.QueueUserWorkItem(new WaitCallback(RemoteUserManagerClient.CreateUser), taskInfo);
}
static public void CreateUser(object stateInfo)
{
CreateUserTaskInfo ti = (CreateUserTaskInfo)stateInfo;
//use ti in the method and access the properties, it will be
// the same object as taskInfo from the other method
}
Upvotes: 3
Reputation: 1008
Using a lambda expression is indeed the easiest way.
However, not using the state argument of the ThreadPool.QueueUserWorkItem to pass along arguments should be considered an anti-pattern:
The following consistently works in my app:
var parm = new ParallelInput()
{
threadIdNbr = threadId,
input = input,
inputLength = inputLen,
leftBlock = leftBlock,
leftBlockLength = leftBlockLength,
leftSiblingThreadData = leftSiblingThreadData,
rightSiblingThreadData = rightSiblingThreadData,
threadCommon = threadCommon,
globalOutputWriter = globalOutputWriter,
threadWrittenAllCounter = threadWrittenAllCounter
};
ThreadPool.QueueUserWorkItem(pp => { var p = (ParallelInput)pp; rdr.parallelConvert(p.threadIdNbr, p.input, p.inputLength, p.leftBlock, p.leftBlockLength, p.leftSiblingThreadData, p.rightSiblingThreadData, p.threadCommon, p.globalOutputWriter, p.threadWrittenAllCounter); }, parm);
... and the following consistently fails on my hardware :
ThreadPool.QueueUserWorkItem(_ => rdr.parallelConvert(threadId, input, inputLen, leftBlock, leftBlockLength, leftSiblingThreadData, rightSiblingThreadData, threadCommon, globalOutputWriter, threadWrittenAllCounter), null);
... since it fails to provide all data within the input array. (Tested with VS2010 and .NET v4.0.30319)
Upvotes: 0
Reputation: 171188
The most convenient method is to use a lambda expression:
var localVariable = 42;
ThreadPool.QueueUserWorkItem (_ => { Console.WriteLine(localVariable); }, null);
This is the most sane way to use this API.
The C# compiler will generate a class internally. This method is (virtually) as fast as using a class explicitly.
Upvotes: 1
Reputation: 65436
Just cast your state object back, which also applies for ParameterizedThreadStart:
List<string> list = new List<string> {"1","2","3"};
ThreadPool.QueueUserWorkItem (CallBack, list);
void CallBack(object state)
{
List<string> list = (List<string>) state;
}
Upvotes: 3
Reputation: 74909
The second parameter can be an array but you're better off creating a custom class for containing your data. That way the data you pass is fully typed.
Upvotes: 4
Reputation: 27727
All types in .NET derive from object so you can pass in anything you want to QueueUserWorkItem. Just cast it in your WaitCallback method.
Upvotes: 1
Reputation: 4780
Yes the type of the argument is System.Object so you can pass anything. http://msdn.microsoft.com/en-us/library/4yd16hza.aspx
Upvotes: 3