簡體   English   中英

C#中的線程池

[英]ThreadPool in C#

我有兩個問題:

  1. 有沒有一種方法可以插入不將對象作為參數的ThreadPool函數(要向threadPool中插入函數,它必須是返回void並賦予一個參數-object的函數),例如我想插入此函數: double foo(int a,double b,string c)嗎?
  2. 有沒有辦法wait線程進入池中(例如加入)?

對於第一部分,最簡單的方法可能是:

根據您的描述假設一種方法:

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轉換為對象以將其傳遞給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);

因此,您不需要更改當前函數中的任何代碼...

做到這一點的經典方法如下,但是Iridium已經表明,現在有更緊湊的方法。 如果您使用的是.NET 4,則可以使用並行API或更精確地使用Tasks來簡化它。

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類中的事件,Action或Func將是另一個解決方案。

我建議閱讀Joe Albahari關於線程的免費電子書 ,因為它涵蓋了更多主題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM