ThreadPool in C#

本文关键字:in ThreadPool | 更新日期: 2023-09-27 18:18:41

我有两个问题:

  1. 是否有一种方法来插入一个ThreadPool函数,不得到对象作为参数(要插入一个函数到threadPool,它需要是返回void和一个参数-对象的函数),例如我想插入这个函数:double foo(int a,double b,string c) ?
  2. 是否有办法wait线程池(如连接)?

ThreadPool in C#

对于第一部分,最简单的方法可能是:

假设一个方法符合你的描述:

public double foo(int a, double b, string c)
{
    ...
}

你可以在线程池中排队:

ThreadPool.QueueUserWorkItem(o => foo(a, b, c));

对于第二部分,虽然不能等待ThreadPool线程,但可以在线程池上异步调用方法,并等待它们完成(这似乎是您正在寻找的)。

同样,假设Foo方法如上所述定义。

为Foo定义一个委托:

private delegate double FooDelegate(int a, double b, string c);

然后使用FooDelegate的BeginInvoke/EndInvoke方法异步调用Foo:

// Create a delegate to Foo
FooDelegate fooDelegate = Foo;
// Start executing Foo asynchronously with arguments a, b and c.
var asyncResult = fooDelegate.BeginInvoke(a, b, c, null, null);
// You can then wait on the completion of Foo using the AsyncWaitHandle property of asyncResult
if (!asyncResult.CompletedSynchronously)
{
    // Wait until Foo completes
    asyncResult.AsyncWaitHandle.WaitOne();
}
// Finally, the return value can be retrieved using:
var result = fooDelegate.EndInvoke(asyncResult);

回答评论中提出的问题。如果您想并行执行多个函数调用,并在继续之前等待它们全部返回,您可以使用:

// Create a delegate to Foo
FooDelegate fooDelegate = Foo;
var asyncResults = new List<IAsyncResult>();
// Start multiple calls to Foo() in parallel. The loop can be adjusted as required (while, for, foreach).
while (...)
{
    // Start executing Foo asynchronously with arguments a, b and c.
    // Collect the async results in a list for later
    asyncResults.Add(fooDelegate.BeginInvoke(a, b, c, null, null));
}
// List to collect the result of each invocation
var results = new List<double>();
// Wait for completion of all of the asynchronous invocations
foreach (var asyncResult in asyncResults)
{
    if (!asyncResult.CompletedSynchronously)
    {
        asyncResult.AsyncWaitHandle.WaitOne();
    }
    // Collect the result of the invocation (results will appear in the list in the same order that the invocation was begun above.
    results.Add(fooDelegate.EndInvoke(asyncResult));
}
// At this point, all of the asynchronous invocations have returned, and the result of each invocation is stored in the results list.

这两个问题的答案都是否定的,不能用本机ThreadPool,尽管如果您将输入参数打包到状态对象中并编写机制来提供等待功能并获得工作项方法的结果,您可以获得相同的结果。

http://smartthreadpool.codeplex.com/做你想做的一切;

    public static void Main(string[] args)
    {
        var threadPool = new SmartThreadPool();
        IWorkItemResult<int> workItem=null;
        SmartThreadPool.WaitAll(new IWaitableResult[ ]{workItem = threadPool.QueueWorkItem(new Amib.Threading.Func<int, int, int>(Add), 1, 2)});
        Console.WriteLine(workItem.Result);
        Console.ReadLine();
    }
    public static int Add(int a, int b)
    {
        return a+b;
    }

关于你的第一个问题,创建一个正确签名的新方法(返回void,一个对象参数),调用foo。如果你需要向foo传递特定的参数,那么创建一个类或结构,或者使用Tuple<int, double, double>并将其强制转换为对象,将其传递给ThreadMethod,然后返回到Tuple以获得foo的参数。

void ThreadMethod(object obj)
{
    var args = (Tuple<int, double, double>)obj;
    foo(args.Item1, args.Item2, args.Item3);
}

再保险。第二个问题,你必须自己创建线程,这样你就可以保留一个Thread对象来加入。

对于第一个问题

我认为你可以创建一个新的类作为参数

例如

interface IAction
{
    void Do();
}

    class SubClass : IAction
    {
        object _param;
        public SubClass(object o)
        {
            _param = o;
        }
        public void Do()
        {
           // your current code in here
        }
    }

        SubClass sc = new SubClass("paramter");
        System.Threading.ThreadPool.QueueUserWorkItem(action => {
            var dosomething = action as IAction;
            dosomething.Do();
        }, sc);

经典的方法如下,但是正如铱星公司所展示的,现在有更紧凑的方法。如果你正在使用。net 4,你可以使用并行api或更精确的任务,使它更容易。

public class MyWorker
{
    private int _a;
    private double _b;
    private string _c;
    Action complete
    public MyWorker(int a,double b,string c)
    {
        _a = a;
        _b = b;
        _c = c;
    }
    public void Run(object state)
    {
        double result = Foo();
    }
    private double Foo()
    {
        // Do something with _a, _b, _c
    }
}
MyWorker worker = new MyWorker(1,1,"");
ThreadPool.QueueUserWorkItem(worker.Run);

在MSDN页面上有一个类似的例子。

当线程池中的线程完成时,可以使用WaitHandle通知在对象内部。假定您不想在线程完成之前阻塞,其中如果在MyWorker类中使用event, Action或Func将是另一种解决方案。

我推荐阅读Joe Albahari关于线程的免费电子书,因为它涵盖了更多细节。