Многопоточность в C #: как передать имя функции другой функции, чтобы начать новый поток? - PullRequest
4 голосов
/ 18 февраля 2009

Я использую многопоточность в своем коде C # следующим образом:

Thread startThread;

public void NewThread()
{
   ThreadStart starter = delegate { foo(); };
   startThread = new Thread(starter);
   startThread.Start();
}

private void foo()
{
   //do some work
}

И затем в моем приложении я вызываю NewThread () для запуска нового потока.

Но теперь у меня много потоков в каждом классе, и у каждого есть свой собственный NewThread (), я думал переместить это в статический класс Util и передавать ему имя функции каждый раз, когда я хочу создать новый поток эта функция.

Знаете ли вы, как это лучше всего сделать, если да, как я могу передать имя функции в качестве параметра?

Ответы [ 6 ]

4 голосов
/ 18 февраля 2009

Ну, так как метод является частным, имеет ли смысл для вызывающей стороны знать имя метода? Если бы он был общедоступным, вы могли бы передать метод в:

public void NewThread(Action task)
{
   ThreadStart starter = delegate { task(); };
   startThread = new Thread(starter);
   startThread.Name = task.Method.Name;
   startSpoolerThread.Start();
}

public void foo()
{
   //do some work
}

NewThread(obj.foo);

Однако для частного метода я подозреваю, что enum / switch - лучший вариант ...

NewThread(TasktType.Foo);

Кроме того, вы можете получить метод с помощью отражения ...

public void NewThread(string name)
{
    MethodInfo method = GetType().GetMethod(name,
        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
        null, Type.EmptyTypes, null);
    ThreadStart starter = delegate { method.Invoke(this, null); };
    // etc (note: no point using Delegate.CreateDelegate for a 1-call usage
3 голосов
/ 18 февраля 2009

Если нет конкретной причины, по которой вы явно создаете потоки, почему бы не использовать Threadpool? Метод Threadpool.QueueUserWorkItem принимает делегата в качестве единицы работы для выполнения. Делегат относится к конкретному типу, но вы можете заключить в него свой собственный вызов делегата, как в своем примере. Если вам не нужен точный контроль или отмена, в целом лучше использовать пул потоков, а не раскручивать потоки самостоятельно.

1 голос
/ 18 февраля 2009

Я бы посоветовал вам также взглянуть на CTP API-интерфейсов задач Parallel Extensions; Вы не упоминаете, зачем вам нужна ветка, но они автоматизировали большую часть этого , вот ссылка на их блог

0 голосов
/ 18 февраля 2009

Делегаты уже предоставляют метод для их асинхронного выполнения. Например:

delegate void dowork();
private static void WorkDone(IAsyncResult result)
{
   ((dowork)result.AsyncState).EndInvoke(result);
    // this function is called when the delegate completes
}
public void Start()
{
    dowork dw = delegate {// code in this block has it's own thread };
    dw.BeginInvoke(WorkDone, null);
}

Таким образом, чтобы передать указатель на функцию, нужно создать делегата с правильной сигнатурой (в этом случае я использовал анонимный метод, но вы можете использовать любую функцию с правильной сигнатурой) и вызвать ее BeginInvoke. метод, передающий функцию, которая будет вызвана, когда она будет завершена ... эта функция должна затем вызвать EndInvoke для исходного делегата, который передается в функцию WorkDone в параметре результата.

0 голосов
/ 18 февраля 2009

В качестве альтернативы, если вы работаете с Win.Forms или аналогичным приложением с графическим интерфейсом, я бы рекомендовал использовать BackgroundWorker . Он выполняет маршаллинг для большинства событий, связанных с потоками, и также гораздо менее сложен для прерывания (если это то, что вам нужно сделать).

0 голосов
/ 18 февраля 2009

Взгляните на следующую статью о Codeproject " Poor Man's Parallel.ForEach Iterator " Я думаю, что это именно то, что вы ищете. Очень прост в использовании.

Для чего-то более мощного также взгляните на Power Threading Library .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...