ThreadPool в C # - PullRequest
       13

ThreadPool в C #

1 голос
/ 21 декабря 2011

У меня два вопроса:

  1. Есть ли способ вставить фунтоин ThreadPool, который не получает объект как параметр (для вставки функции в threadPool должна быть функция, которая возвращает void и дает один параметр -object), например, я хочу вставить эту функцию: double foo(int a,double b,string c)?
  2. Есть ли способ wait для потоков в пуле (например, объединение)?

Ответы [ 5 ]

5 голосов
/ 21 декабря 2011

Для первой части, вероятно, самый простой подход:

Принимая метод согласно вашему описанию:

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 асинхронно, используя методы BeginInvoke / EndInvoke объекта 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.
2 голосов
/ 21 декабря 2011

Ответ на оба эти вопроса - нет, не с помощью собственного 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 голосов
/ 21 декабря 2011

Классический способ сделать это ниже, однако, как показал Иридиум, есть более компактные способы сделать это сейчас.Если вы используете .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 будет другим решением.

Я бы рекомендовал прочитать Джо Албахарибесплатная электронная книга по теме Threading as, которая более подробно описывает темы.

0 голосов
/ 21 декабря 2011

За первый вопрос

Я думаю, вы можете создать новый класс в качестве параметра

для примера

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

Итак, вам не нужно менять какой-либо код в вашей текущей функции ...

0 голосов
/ 21 декабря 2011

По первому вопросу создайте новый метод правильной подписи (возвращает 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.2-й вопрос, вам нужно будет создать поток самостоятельно, чтобы вы могли оставить объект Thread для соединения.

...