5YrsLaterDBA
5YrsLaterDBA

Reputation: 34770

C# Can I pass more than one data into my target method when using ThreadPool?

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

Answers (7)

Scott Chamberlain
Scott Chamberlain

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

Wolfgang Grinfeld
Wolfgang Grinfeld

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

usr
usr

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

Chris S
Chris S

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

Samuel Neff
Samuel Neff

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

Jake Pearson
Jake Pearson

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

btlog
btlog

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

Related Questions