2011-12-21 2 views
1

У меня есть два вопроса:ThreadPool в C#

  1. Есть ли способ, чтобы вставить ThreadPool functoin что dosen't получает объект в качестве параметра (вставить функцию Threadpool она должна быть функция, которая возвращается тщетным и 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)); 

Для второй части, в то время как вы не можете ждать на ThreadPool нить, вы можете вызывать методы асинхронно в пуле потоков и ждать их завершения (что похоже на то, что вы ищете).

Опять же, предполагая, что метод Foo определен выше.

Определение делегата для Foo:

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

Затем вызвать Foo асинхронно с помощью/EndInvoke методы BeginInvoke на FooDelegate:

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

Вы можете бросить петлю вокруг вашего примера, это то, что мне нужно, но у меня возникли проблемы с тем, как его зацикливать (иметь несколько вызовов функций), когда вы просто сидите там, ожидая результата первого вызова. – ganders

+1

@ganders Я сделал редактирование ответа, чтобы ответить на ваш вопрос. Если вам нужна дополнительная информация, я предлагаю вам задать отдельный вопрос. – Iridium

+0

оцените быстрый ответ Иридиум. Является ли переменная результатов в цикле while предполагаемой переменной asyncResults? – ganders

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 для справки –

+0

Спасибо. Я использовал STP для хорошего эффекта много раз, и это хорошо известный компонент http://stackoverflow.com/questions/8429938/maximum-concurrency-throttle –

0

Re ваш первый вопрос, создать новый метод правильной подписи (возвращает недействительным, один объект параметр), который вызывает 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. Вот и все! моя функция должна быть в этой подписи, я не могу ее изменить. 2. Я хочу вставить его в пул. – aharon

+0

Создайте новую функцию, которая вызывает тот, который не может измениться. –

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

Классический способ сделать это ниже, однако, как 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 page.

Что касается уведомлений о завершении потока в потоковом пуле, вы можете использовать WaitHandle внутри объекта. Предположительно, вы не хотите блокировать до тех пор, пока поток не будет завершен, в случае которого событие будет другим событием, действием или Func в классе MyWorker.

Я бы рекомендовал прочитать Joe Albahari's free ebook о Threading, так как он охватывает предметы намного подробнее.

Смежные вопросы