Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Пул потоков.


Страницы:   1 2 3 4 5 6

panov ©   (2004-10-14 14:34:00) 

Создал класс для работы с пулом потоков.
Прошу высказать замечания.
В следующих постингах задам вопросы к коду.


unit uTThreadPool;

interface

uses
 Classes, windows, messages;

var
 WM_EndThreadExecuter: DWORD;      //Сообщение об окончании обработки
 WM_AddThread: DWORD;              //Сообщение о добавлении элемента в очередь

type
//Тип процедуры для выполнения в отдельном потоке
 TThreadProc=procedure(aParm: pointer);

//Структура для передачи параметров
 PQueueRec=^TQueueRec;
 TQueueRec=record
   rProc: TThreadProc;
   rParm: Pointer;
 end;

//Элемент пула потоков
 TThreadExecuter=class(TThread)
 private
   FThreadIdOwner: THandle;        //Родительский поток TThreadPool
   FThreadFree: Boolean;           //Поток свободен/занят работой
   FExecProc: TThreadProc;         //Адрес процуедуры для выполнения
   FParm: Pointer;                 //Указатель на параметр,
                                   //Предаваемый в процедуру FExecProc
   FNumThread: Integer;            //Нмер потока в пуле
 protected
   procedure Execute; override;
 public
//В конструктор передается ThreadId родительского потока TThreadPool
   constructor Create(const aOwnerThread: THandle;const aNumThread: Integer);
 end;

//Менеджер пула потоков TThreadExecuter
 TThreadPool = class(TThread)
 private
{ TODO -cВажно :
Добавить код для проверки работоспособности потоков из пула
Зависшие убивать по таймауту }
   FSemaphore: THandle;            //Семафор-счетчик потоков
   FMaxThreads: Integer;           //Максимальное число потоков в пуле
   FListQueue: TList;              //Очередь заданий на выполнение
   FPool: array of TThreadExecuter; //Пул потоков
   procedure JobAdd(const aProc: TThreadProc;const aParm: Pointer); //Добавление
                                                                    //заданий в очередь
   function StartThreadFromQueue: Boolean; //Передача задания из очереди в пул
                                           //на выполнение
 protected
   procedure Execute; override;
 public
//В конструктор передается максимальное число потоков
   constructor Create(aMaxThreads: Integer);
   destructor Destroy;override;
//Добавление заданий из внешних потоков в очередь потоков
//Параметры:
//  aProc - адрес процедуры для выполнения
//  aParm - адрес памяти, по которуму нахлодятся параметры
//          для выполнения прцедуры
   procedure AddThread(aProc:TThreadProc;aParm:Pointer);
 end;

implementation

uses Unit1;

{ TThreadExecuter }

constructor TThreadExecuter.Create(const aOwnerThread: THandle;const aNumThread: Integer);
begin
 inherited Create(True);
 FreeOnTerminate := True;
 FThreadFree := True;
 FThreadIdOwner := aOwnerThread;
 FNumThread := aNumThread;
 Resume;
end;

procedure TThreadExecuter.Execute;
begin
 while not Terminated do
 begin
   Suspend;                        //Засыпаем сразу
   try
     if Assigned(FExecProc) then FExecProc(FParm); //Выполнение переданной
                                                   //процедуры
   except
   end;
//Передача в родительский поток сообщения о завершении обработки
   PostThreadMessage(FThreadIdOwner,WM_EndThreadExecuter,FNumThread,0);
   if Terminated then break;
 end;
end;


Суслик   (2004-10-14 18:38:00) [61]


>  [50] Verg ©   (14.10.04 18:37)

может и путаю. Но опыт сравнения быстродействия mutex и кс в свое время сказал мне о многом.


Verg   (2004-10-14 18:37:00) [62]


> Есть не ошибаюсь, критические секции доходят до использования
> ОЯ только в случае коллизий.


Не путаете ли вы понятия "обходиться без" и "использовать эффективно".
Если КС использует ОЯ эффективно, это не означает, что она их вообще не использует.


Суслик   (2004-10-14 18:30:00) [63]


> Посмотри, как реализованы критические секции и зачем там
> объект ядра LockSemaphore.

Где?

Есть не ошибаюсь, критические секции доходят до использования ОЯ только в случае коллизий. Источник: рихтер, win для профи, стр 202. Т.е. большинство операций выполняются в польз. режиме.
В случае же использования ОЯ переход в реж. ядра происходит сразу. Истоник: тот же. + опыт сранения быстродействия.


Игорь Шевченко   (2004-10-14 18:20:00) [64]

Суслик ©   (14.10.04 18:11) [46]


> Возражения есть?


Есть.

Посмотри, как реализованы критические секции и зачем там объект ядра LockSemaphore.


panov   (2004-10-14 18:16:00) [65]

>Игорь Шевченко ©   (14.10.04 18:08) [45]
Ну можно, конечно, и на основе портов ввода-вывода, только работать в w98 они не будут...


Суслик   (2004-10-14 18:11:00) [66]


>  [44] Игорь Шевченко ©   (14.10.04 18:07)

Игорь, хватит придираться, ты прекрасно понимаешь о чем я? Нет?

Тогда напомню, что я тебя спрашивал как работает этот класс, ты сказал, что там ничего сложного. Если так, то ты не можешь не знать, что многие действия, для которых можно было бы применить ОЯ для синхронизации обходятся без оных. В качесвте примера см. TThreadLocalCounter.

Мое утверждение было о том, что при синхронизации не обязательно использовать ОЯ. И класс был приведен в качестве пример такой реализации.

Возражения есть?


Игорь Шевченко   (2004-10-14 18:08:00) [67]


> Создал класс для работы с пулом потоков.


Рихтер тоже создал, только на основе IOCompletion, если мне память не изменяет.


Игорь Шевченко   (2004-10-14 18:07:00) [68]


> Все же, есть способы объходиться без ОЯ. Например см. класс
> TMultiReadExclusiveWriteSynchronizer. Там реализована очень
> скорострельная синхронизация БЕЗ объектов ядра. Если интересно
> смотри его.


constructor TMultiReadExclusiveWriteSynchronizer.Create;
begin
 inherited Create;
 InitializeCriticalSection(FLock);
 FReadExit := CreateEvent(nil, True, True, nil);  // manual reset, start signaled
 SetLength(FActiveThreads, 4);
end;

Типа того, что CreateEvent - это уже не создание объекта ядра.


Суслик   (2004-10-14 17:31:00) [69]


>  [42] panov ©   (14.10.04 17:29)

Оптимальность, понятие неоднозначное. Я уверен, что в текущей задаче путь с использование ОЯ будет наиболее оптимальный, т.к.:
1. Позволит доделать класс за 10 мин.
2. Точно не окажет негативного влияния на скорость.


panov   (2004-10-14 17:29:00) [70]

>Суслик ©   (14.10.04 17:27) [41]

Смысл ведь имеет не конкретная задача, а наиболее отимальное универсальное решение.

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

Если прикинуть, то такая задача "на скорострельность" может иметь применение при расчетах в графических динамичных приложениях...


Суслик   (2004-10-14 17:27:00) [71]


>  [40] panov ©   (14.10.04 17:24)

я не говорил, что его надо исполозовать. Я говорил, что в его коде используется синхронизация без ОЯ. Вот и все. Причем такая синхронизация, которую не сразу и поймешь. Я вроде разобрался. Но вопротить вряд ли смогу.

Все же хотелось бы услышать ответ на вопрос [38]. Может устроить тесты и выяснить, что собственно ОЯ вполне удовлетворяют? Я бы начал с этого. Я когда-то делал такое сравнение. И скажу честно, что я не смог придумать задачу для своих целей, где бы скорострельности event'ов мне бы не хватало.


panov   (2004-10-14 17:24:00) [72]

Кстати, насчет TMultiReadExclusiveWriteSynchronize.

Как я понял, единственное, что мне даст, это то, что мне не надо несколько критических секций использовать, и объекты для ожидания создаются статически всего 2.


Суслик   (2004-10-14 17:09:00) [73]


> [36] panov ©   (14.10.04 16:56)
> Никаких проблем нет. Какая синхронизация? Потоками управляет
> ровно один поток - пуллер. Что хош, то и делай там.
>
> Уже обсуждали, что Execute выполняется позде, чем происходит
> обюращение к прочим методам объекта.

И вообще, никакие уловки, кроме как применять методы синхронизации, не спасут от проблемы, когда поток начинает использоваться раньше, чем начинает работать его поточная ф-я. Вот.


Суслик   (2004-10-14 17:07:00) [74]

Мне как-то не очень понятно, что эта за задача такая, где требуется такое титаническое быстродействие?


Суслик   (2004-10-14 17:01:00) [75]


> Уже обсуждали, что Execute выполняется позде, чем происходит
> обюращение к прочим методам объекта.

ух... сложно как-то. Все-таки предложение увидеть модифицированный код, и продолжить обсуждение от новой отправной точки.


panov   (2004-10-14 16:56:00) [76]

Никаких проблем нет. Какая синхронизация? Потоками управляет ровно один поток - пуллер. Что хош, то и делай там.

Уже обсуждали, что Execute выполняется позде, чем происходит обюращение к прочим методам объекта.


Суслик   (2004-10-14 16:33:00) [77]

у рихтера есть про очередь потоков. Может там стоит посмотреть?


Суслик   (2004-10-14 16:24:00) [78]


> Может быть, у кого еще будут предложения по синхронизации
> без использования объектов ядра, подобных Event

Ну, Александр, я же привел пример TMultiReadExclusiveWriteSynchronizer. Там то, что нужно. Только разбираться долго надо. Там нет объектов ядра, но есть синхронизация. Там все сделано на interloced функциях.


> >Суслик ©   (14.10.04 16:07) [31]
> Семафор удобен для счетчика потоков в пуле и сигнализирования
> о том, что есть свободные потоки.

Не, ну вы гляньте :))) Не хочется использовать ОЯ (медленные), а вот семафор (тоже ОЯ) для целей, где он не нужен используется радостно. Не пойму. На фига он тут нужен - к нему обращается всего один поток!


> Как раз из-за проблем с синхронизацией она такая-)

Никаких проблем нет. Какая синхронизация? Потоками управляет ровно один поток - пуллер. Что хош, то и делай там.


panov   (2004-10-14 16:20:00) [79]

>Суслик ©   (14.10.04 16:03) [30]
2. Реализовать синхронизацию в целях обеспечения своевременности создания очереди.

Как раз это и хотелось обсудить.
Может быть, у кого еще будут предложения по синхронизации без использования объектов ядра, подобных Event

>Суслик ©   (14.10.04 16:07) [31]

И вообще - на фига тут FSemaphore: он же используется в контексте одного потока?


Семафор удобен для счетчика потоков в пуле и сигнализирования о том, что есть свободные потоки.

>Суслик ©   (14.10.04 16:12) [32]
Странная какая-то эта функция StartThreadFromQueue.

Как раз из-за проблем с синхронизацией она такая-)


Суслик   (2004-10-14 16:12:00) [80]


> [27] panov ©   (14.10.04 15:59)
> >Суслик ©   (14.10.04 15:55) [25]
>
> Функция StartThreadFromQueue должна возвращать True в единственном
> случае - при передаче задания на выполнение.
> В остальных случаях возвращается False.

Странная какая-то эта функция StartThreadFromQueue.
Ей говорят - запусти задание из очереди. Она - ок! Все потоки заняты, но макс. количества потоков не достигнут. Она создает новый поток и возврщает false. Тем самым говоря, клиенту (вызывающей стороне), то все, что могла она запустила. Странно как-то: поток есть (только что создан), задание есть, а вот выполнять его никто ПОКА не собирается - ждем следующего цикла.


Страницы:   1 2 3 4 5 6

Наверх

Титульная страница Поиск, карта сайта Написать письмо