суббота, 15 ноября 2008 г.

Работа с потоками

Что делать, если хочется оптимизировать программу научив ее работать с несколькими потоками, а стандартный BackgroundWorker помочь не может (как минимум потому, что создает только 1 поток)? Например, если хочется распараллелить цикл на максимально-доступное количество потоков в соответствии с текущим процессором?

Можно это сделать разными сложными путями, например, используя класс Thread. А можно пойти простым путем. Вот про него-то я и расскажу ниже.

Существует такой замечательный класс - ThreadPool. Во-первых, он умеет запускать именно столько потоков, сколько можно на текущей машине, а остальные ставит в очередь. А во-вторых, он позволяет просто решить проблему с ожиданием окончания работы запущенных потоков.

Добавить новый поток в очередь очень просто:
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), waitHandle);
где метод DoTask:
void DoTask(Object state)
причем параметр waitHandle передается как Object state, но об этом попозже.

Дождаться завершения работы всех потоков можно вот так (на самом деле там куча вариантов - читайте документацию):

WaitHandle[] waitHandles = new WaitHandle[] { waitHandle };
WaitHandle.WaitAll(waitHandles);
Самое замечательное, что можно дожидаться завершения любого из потоков:


WaitHandle[] waitHandles = new WaitHandle[] { waitHandle };
WaitHandle.WaitAny(waitHandles);
Ну и последнее - про переменную waitHandle. Если ее проинициализировать вот так:
WaitHandle waitHandle = new AutoResetEvent(false);
... то в теле нашего метода DoTask можно будет (даже нужно!) оповестить о том, что метод завершил свою работу. Примерно вот так:


AutoResetEvent are = (AutoResetEvent)state;
are.Set();
Ну вообщем-то и все :) Пользуйтесь. Естественно, что от всех "прелестей" многопоточного приложения это вас не спасёт.

P.S.: пытался заставить мой переводчик переводить каждое предложение в отдельном потоке (точнее по два предложения за раз) - глухо. Где-то идут конфликты в обращениях к данным и в итоге код, который раньше в одном потоке работал без ошибок начинает падать. Причем очень странно падать - сообщения вида NullRefernceException при том, что там, куда указывает отладчик - null-значений вообще нет и взяться им неоткуда. Мистика :(

Никто не встречал программы, которая могла бы проанализировав код ткнуть пальцем и сказать, что вот тут и тут работать не будет в многопоточном приложении? Ибо перелопатить текущий код просто нереально - дешевле с нуля написать :(

Комментариев нет:

Отправить комментарий