2011-12-21 112 views
1

我有兩個問題:線程池在C#

  1. 有沒有一種方法來插入ThreadPool functoin是這麼想的獲取 對象作爲參數(插入函數線程池就必須返回void功能和ged一個參數 - 對象)例如,我想插入此函數:double foo(int a,double b,string c)
  2. 有沒有一種方法wait線程池(如加入)?

回答

5

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

假設按你的描述方法:

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

你可以用線程池排隊這樣的:

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

對於第二個部分,雖然你不能在一個線程池線程等待,你可以在線程池上異步調用方法,並等待它們完成(這似乎是你正在尋找的)。

再次,假定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); 

爲了解決在意見中提出的問題:

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

然後美孚異步使用FooDelegate的的BeginInvoke/EndInvoke會的方法來調用。如果你想在並行執行多個函數調用,並等待他們全部繼續之前返回,你可以使用:

// 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. 
+0

你可以在你的例子中引入一個循環,這是我需要的,但是當你只是坐在那裏等待第一次調用的結果時,看不到如何循環它(有多個函數調用)。 – ganders 2012-08-30 13:50:14

+1

@ganders我已經編輯瞭解答您的問題的答案。如果你需要進一步的細節,我建議你發佈一個單獨的問題。 – Iridium 2012-08-30 14:24:27

+0

欣賞銥星的快速反應。 while循環中的結果變量應該是asyncResults變量嗎? – ganders 2012-08-30 14:57:21

2

這兩個問題的答案都是否定的,不是原生的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; 
    } 
+0

+1僅供參考 – 2011-12-21 09:23:36

+0

謝謝。我已經使用STP很好的效果很多次,它是一個很好的組件http://stackoverflow.com/questions/8429938/maximum-concurrency-throttle – 2011-12-21 09:25:18

0

回覆您的第一個問題,建立正確的簽名的新方法(返回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); 
} 

Re。第二個問題,你必須自己創建線程,以便你可以保留一個Thread對象加入。

+0

1.多數民衆贊成的重點!我的功能必須在這個簽名中,我不能改變它。我想將它插入池中。 – aharon 2011-12-21 09:18:25

+0

創建一個調用無法更改的新函數。 – 2011-12-21 09:18:47

0

對於第一個問題

我想你可以創建一個新的類作爲參數

爲exsample

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); 

所以,你donnt需要更改您的當前功能的任何代碼。 ..

0

做它的經典方法是下面,但銥星已經顯示出有更緊湊的方式現在就做。如果您使用.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 page上有一個等效的例子。

在線程池中的線程完成時收到通知時,可以在對象內部使用WaitHandle 。大概你不想阻塞,直到線程完成,其中 事件,MyWorker類中的Action或Func將是另一個解決方案。

我建議閱讀關於Threading的Joe Albahari's free ebook,因爲它涵蓋了更多細節的主題。