Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.04.23;
Скачать: CL | DM;

Вниз

wait functions   Найти похожие ветки 

 
Polevi ©   (2006-02-01 12:09) [0]

несколько потоков ждут семафор
насколько возможно предсказать в каком порядке потоки проснуться при вызове ReleaseSemaphore ?
FIFO, LIFO или случайным образом ?

у меня есть пул потоков который обслуживает запросы клиентов
пул наращиваемый, алгоритм удаления потока следующий - он удаляется если ждет объекта более 1 минуты к примеру
я опасаюсь что данный алгоритм не будет работать если потоки будут получать управление в порядке вызова ими Wait ф-ии, в моем случае они будут получать управление по очереди даже если будет только один клиент

какие будут соображения, господа ?


 
Игорь Шевченко ©   (2006-02-01 12:29) [1]


> насколько возможно предсказать в каком порядке потоки проснуться
> при вызове ReleaseSemaphore ?


Насколько я знаю, FIFO


 
Leonid Troyanovsky ©   (2006-02-01 12:34) [2]


> Polevi ©   (01.02.06 12:09)  

> какие будут соображения, господа ?


У Соломона-Руссиновича оно подробно изложено, кое-что - у Таненбаума,
если мне не изменяет склероз.
Т.е., насколько я помню, для выборов из равноприоритетных потоков
используется витиеватый алгоритм, который, IMHO, не документирован.

--
Regards, LVT.


 
Digitman ©   (2006-02-01 12:41) [3]


> Polevi ©   (01.02.06 12:09)


А зачем ты уничтожаешь объект-трэд по тайм-ауту ?
Только лишь из-за экономии ресурсов ?
Ведь создание и старт трэда сродни пуску холодного автодвигателя !
Не проигрываешь ли ты в скорости реакции приложения на кл.запросы, пытаясь выиграть в ресурсах ?


 
Polevi ©   (2006-02-01 12:45) [4]

тест показал что FIFO, что очень жаль
в моем случае нужен LIFO


 
Polevi ©   (2006-02-01 12:50) [5]

>Digitman ©   (01.02.06 12:41) [3]
это все настраивается значениями таймаутов
доп поток создается при наличие в очереди запроса ожидающего больше X, уничтожается если ничего не делает больше Y


 
Игорь Шевченко ©   (2006-02-01 12:51) [6]


> в моем случае они будут получать управление по очереди даже
> если будет только один клиент


То есть, каждый поток вызывает WaitForSingleObject с таймаутом в минуту, после освобождения семафора они просыпаются все, и каждый решает, что именно он должен обслуживать запрос ? Или по WAIT_TIMEOUT они все удаляются ?


 
Polevi ©   (2006-02-01 13:21) [7]

например есть 3 потока и один клиент
пул потоков выглядит так - в порядке вызова Wait ф-ии
1
2
3
клиент поместил запрос в очередь и вызвал ReleaseSemaphore(H,1,nil);
проснулся поток 1, выбрал запрос из очереди, обработал и вновь вызвал Wait ф-ию
пул потоков теперь такой
2
3
1
т.е. следущий запрос будет обрабатывтаь поток 2, затем 3 и так по кругу
и ни один из них не дождется WAIT_TIMEOUT и не уничтожится

PS
эксперимент показал что SetThreadPriority никак не влияет на порядок


 
Игорь Шевченко ©   (2006-02-01 14:03) [8]


> и вызвал ReleaseSemaphore(H,1,nil);
> проснулся поток 1


Разве не все потоки проснулись ?


 
Polevi ©   (2006-02-01 14:04) [9]

с какой радости


 
Polevi ©   (2006-02-01 14:05) [10]

проснется столько сколько я укажу в ReleaseSemaphore


 
Digitman ©   (2006-02-01 14:34) [11]


> проснется столько сколько я укажу в ReleaseSemaphore


здесь, пожалуйста. подробнее ..


 
Polevi ©   (2006-02-01 15:00) [12]

The ReleaseSemaphore function increases the count of the specified semaphore object by a specified amount.
The state of a semaphore object is signaled when its count is greater than zero and nonsignaled when its count is equal to zero.

каждая ожидающая Wait ф-ия умньшит значение счетчика на 1
когда its count is equal to zero. потоки прекратят свое просыпание

странно что я должен вам это обяъснять если честно


 
Digitman ©   (2006-02-01 15:09) [13]


> Polevi ©   (01.02.06 15:00) [12]


> странно что я должен вам это обяъснять


Работу ф-ции мне не надо объяснять - я ее достаточно четко себе представляю.

А не представляю я другое - каким образом кол-во "пробуждаемых" тобой потоков зависит от параметра lReleaseCount ф-ции ReleaseSemaphore() ..


 
Polevi ©   (2006-02-01 15:13) [14]

напрямую зависит
счетчик=0
10 wait ф-ий ждут пока засигналит объект
я вызвал RS с параметром 2
объект засигналил
в 1 потоке ф-ия возвратила управление уменьшив значение на 1
счетчик =1
объект продолжает сигналить
в 2потоке ф-ия возвратила управление уменьшив значение на 1
счетчик =0
объект не сигналит
оставшиеся потоки ждут след. вызова RS


 
Eraser ©   (2006-02-01 15:17) [15]

по-моему по теме
Тут возникает интересный вопрос. Если несколько потоков ждет один объект ядра, какой из них пробудится при освобождении этого объекта? Официально Microsoft отвечает на этот вопрос так: "Алгоритм действует честно" Что это за алгоритм, Micro soft не говорит, потому что нс хочст связывать себя обязательствами всегда придер живаться именно этого алгоритма. Она утверждает лишь одно- если объект ожидает ся несколькими потоками, то всякий раз, когда этот объект переходит в свободное состояние, каждый из них получает шанс на пробуждение.

Таким образом, приоритет потока не имеет значения- поток с самым высоким приоритетом не обязательно первым захватит объект. Не получает преимущества и поток, который ждал дольше всех. Есть даже вероятность, что какой-то поток сумеет повторно захватить объект. Конечно, это было бы нечестно по отношению к другим потокам, и алгоритм пытается не допустить этого. Но никаких гарантий нет.

Рихтер


 
Digitman ©   (2006-02-01 15:29) [16]


> Polevi ©   (01.02.06 15:13) [14]


Спасибо. Это понятно.

Но непонятна твоя прикладная логика, относящаяся к "вызвал RS с параметром 2".

Почему не 3 ? Или не 1 ? Это же важно, согласись..


 
Rouse_ ©   (2006-02-01 15:32) [17]


> А не представляю я другое - каким образом кол-во "пробуждаемых"
> тобой потоков зависит от параметра lReleaseCount ф-ции ReleaseSemaphore()
> ..

По всей видимости у него сделано по такому принципу:

program Project1;

uses
 Windows, Messages, SysUtils, gssocket;

const
 THREAD_COUNT = 4;

var
 hSemaphore: THandle;
 hThread: array [0..THREAD_COUNT - 1] of THandle;
 lpThreadId, lpPreviousCount: DWORD;
 I: Integer;

procedure ThreadProc(lpParameter: Pointer); stdcall;
var
 hThreadSemaphore: THandle;
begin
 case WaitForSingleObject(hSemaphore, 100000) of
   WAIT_OBJECT_0:
     MessageBox(0, PChar("WAIT_OBJECT_0: " + IntToStr(Integer(lpParameter))), nil, MB_OK);
   WAIT_FAILED:
     MessageBox(0, PChar("WAIT_FAILED: " + IntToStr(Integer(lpParameter))), nil, MB_OK);
   WAIT_TIMEOUT:
     MessageBox(0, PChar("WAIT_TIMEOUT: " + IntToStr(Integer(lpParameter))), nil, MB_OK);
 end;
end;

begin
 hSemaphore := CreateSemaphore(nil, 0, THREAD_COUNT, "TestThreadSemaphore");
 if hSemaphore = 0 then
   RaiseLastOSError;
 for I := 0 to THREAD_COUNT - 1 do
   hThread[I] := CreateThread(nil, 0, @ThreadProc, Pointer(I), 0, lpThreadId);
 lpPreviousCount := THREAD_COUNT;
 Sleep(1000);
 if not ReleaseSemaphore(hSemaphore, 1, @lpPreviousCount) then
   RaiseLastOSError;
 Sleep(2000);
 if not ReleaseSemaphore(hSemaphore, 2, @lpPreviousCount) then
   RaiseLastOSError;
 Sleep(2000);
 if not ReleaseSemaphore(hSemaphore, 1, @lpPreviousCount) then
   RaiseLastOSError;
 Sleep(2000);
end.


Тут наглядно видно. Создается 4 потока. 1 потока отпускаеться через секунду. Потом отпускаються еще два и потом еще один.

Кол-во потоков варьируеться в ReleaseSemaphore


 
Polevi ©   (2006-02-01 15:32) [18]

>Digitman ©   (01.02.06 15:29) [16]
этот параметр равен колву клиентских запросов в очереди


 
Rouse_ ©   (2006-02-01 15:33) [19]

А, ну собственно > Polevi ©   (01.02.06 15:13) [14] сам все рассказал :)


 
Игорь Шевченко ©   (2006-02-01 15:34) [20]

Polevi ©   (01.02.06 15:13) [14]


> оставшиеся потоки ждут след. вызова RS


Или таймаута ?

Я наверное не до конца понимаю, извини

Два рабочих потока ждут освобождения семафора с таймаутом.

Третий поток освободил семафор с ReleaseCount равным единице. Один из потоков проснулся с WAIT_OBJECT_0. Другой поток дождется таймаута ?


 
Polevi ©   (2006-02-01 15:41) [21]

>Игорь Шевченко ©   (01.02.06 15:34) [20]
он его дождется если не будет больше запросов
собственно моя проблема в том, что если один клиент будет каждую секунду посылать запрос - за минуту последовательно проснуться 60 потоков с WAIT_OBJECT_0, до WAIT_TIMEOUT дело не дойдет
вот в случае с LIFO каждый раз бы просыпался поток который посденим вызвал Wait ф-ию а остальные 59 дождались бы таймаута и уничтожились


 
Игорь Шевченко ©   (2006-02-01 15:45) [22]

Polevi ©   (01.02.06 15:41) [21]

Тебе хочется, чтобы на новый запрос просыпался поток, который последним обрабатывал клиентский запрос ? Ты извини за расспросы, я просто понять пытаюсь до конца.


 
Digitman ©   (2006-02-01 15:46) [23]


> Polevi ©   (01.02.06 15:32) [18]
> >Digitman ©   (01.02.06 15:29) [16]
> этот параметр равен колву клиентских запросов в очереди


Тогда вопрос - нашута обрабатывающему некий запрос потоку знать состояние очереди ? Не его это дело ..


 
Rouse_ ©   (2006-02-01 15:53) [24]

Может изменить логику?

1. Пришел запрос - свободных потоков нет - делаем новый, он запрашивает данные и начинает работать.
2. Поток отработал - ставим его на WaitXX (..., INFINITE);
3. Пришел запрос - делаем ReleaseSemaphore. Проснувшийся поток спрашивает свои данные и начинает их выполнять...
Если никто не проснулся, то пункт 1.


 
Polevi ©   (2006-02-01 15:57) [25]

попытаюсь обяснить еще раз что мне надо
у меня наращиваемый пул
необходимо определить условия при которых в него добалвяются и удаляются потоки
алгоритм добавления таков - специальный watch поток следит за очередью клиентских запросов и если находит запрос который лежит там больше X - он добавляет поток в пул
алгоритм удаления был мной сформулирован след. образом - рабочий поток пытается дождаться запроса время Y и если не дожидается - просыпается по таймауту и поняв что делать ему нефиг удаляет себя из пула
допустим в час пик колво потоков достигло 20 а затем пробили куранты все пошли обедать кроме трудоголика васи
вася старательно помылает серверу запросы
вася один а потоков 20
но поскольку работает механизм FIFO на каждый васин запрос будет просыпаться следующий поток, и таймаута ни один из них не дождется

вообщем нужен другой механизм необходимости удаления потока из пула, WAIT_TIMEOUT не подходит


 
Polevi ©   (2006-02-01 15:59) [26]

>Digitman ©   (01.02.06 15:46) [23]
ты не в теме, RS вызывает транспортный поток


 
Polevi ©   (2006-02-01 16:01) [27]

>Rouse_ ©   (01.02.06 15:53) [24]
ну и чем твоя логика отличается от моей интересно

procedure TWorkThread.Execute;
var
 arr:array[0..1] of THandle;
 ir:TInvokeRequest;
 res:TMemoryStream;
 client:TClient;
begin
 arr[0]:=FWaitDataSem;
 arr[1]:=FStopEvent;
 CoInitialize(nil);
 while not Terminated do
 begin
   case WaitForMultipleObjects(2,@arr[0],false,WORKTHREAD_TIMEOUT) of
     WAIT_OBJECT_0: //request
     begin
       ir:=FReqResQueue.GetRequest(client);
       try
         try
           res:=ir.Invoke;
         except on E:Exception do
           res:=CreateExceptionResponse(E.Message);
         end;
         FReqResQueue.AddResponse(client,res);
       finally
         ir.Free;
       end
     end;
     WAIT_TIMEOUT:
     begin
       if FThreadPool.Remove(self) then Terminate;
     end;
     WAIT_OBJECT_0+1: //stop
     begin
       Terminate;
     end
   end;
 end;
 CoUninitialize;
end;


 
Polevi ©   (2006-02-01 16:02) [28]

этот код я привел чтобы показать что после добавления нового потока он обрабатывает запрос и не уничтожается


 
Игорь Шевченко ©   (2006-02-01 16:15) [29]


> но поскольку работает механизм FIFO на каждый васин запрос
> будет просыпаться следующий поток, и таймаута ни один из
> них не дождется


Я вот этого момента честно не понимаю, почему ни один не дождется таймаута ?


 
Digitman ©   (2006-02-01 16:15) [30]


> Polevi ©   (01.02.06 15:59) [26]
> RS вызывает транспортный поток


Тогда поясни, какое дело логике транспортного потока до логики потока-диспетчера пула ?


 
Polevi ©   (2006-02-01 16:27) [31]

>Игорь Шевченко ©   (01.02.06 16:15) [29]
11:00 поток 1 WaitFor(..,10 мин)
11:00 поток 2 WaitFor(..,10 мин)
11:01 request поток 1 WaitFor(..,10 мин)
11:02 request поток 2 WaitFor(..,10 мин)
11:03 request поток 1 WaitFor(..,10 мин)
11:04 request поток 2 WaitFor(..,10 мин)
11:05 request поток 1 WaitFor(..,10 мин)
11:06 request поток 2 WaitFor(..,10 мин)
11:07 request поток 1 WaitFor(..,10 мин)
11:08 request поток 2 WaitFor(..,10 мин)
11:09 request поток 1 WaitFor(..,10 мин)
11:10 request поток 2 WaitFor(..,10 мин)
11:11 request поток 1 WaitFor(..,10 мин)
..
10 мин прошло а таймаута все нет...

>Digitman ©   (01.02.06 16:15) [30]
транспортный поток получил 5 запросов и поместил их в очередь
он сообщает пулу о наличии 5 запросов вызывом RS и идет дальше заниматься своими транспортными делами


 
Игорь Шевченко ©   (2006-02-01 16:45) [32]

Polevi ©   (01.02.06 16:27) [31]


> 10 мин прошло а таймаута все нет...


Разумно, что нет. Частота запросов превышает период ожидания и у тебя запросы обрабатываются несколькими потоками. Может, тебе имеет смысл динамически менять время ожидания в зависимости от количества потоков ?


 
Rouse_ ©   (2006-02-01 16:48) [33]


> но поскольку работает механизм FIFO на каждый васин запрос
> будет просыпаться следующий поток, и таймаута ни один из
> них не дождется

тогда уйди от семафора и перейди на собственный механизм. т.е. некий контролируйщий поток содержит в себе массив, ну... к примеру Event-ов. Все остальные потоки ждут сигнала только от своего Event-а. При срабатывании WaitXX в этом контролирующем потоке, он по нужному тебе алгоритму сделает SetEvent нужному тебе элементу. остальные выйдут по таймауту.


 
Polevi ©   (2006-02-01 16:49) [34]

>Игорь Шевченко ©   (01.02.06 16:45) [32]
уфф, ну наконец чтото конкретное :-)
я собственно и думаю над алгоритмом, принимаю ваши предложения


 
Polevi ©   (2006-02-01 16:56) [35]

>Rouse_ ©   (01.02.06 16:48) [33]
а как я узнаю какой из них нужный
может он занят и освободится через час :)
к тому же их может потребоваться больше одного за раз


 
Игорь Шевченко ©   (2006-02-01 17:02) [36]

Polevi ©   (01.02.06 16:49) [34]

WaitFor(...., DefaultTimeout div NumberOfWorkerThreads).

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


 
Polevi ©   (2006-02-01 17:09) [37]

>Игорь Шевченко ©   (01.02.06 17:02) [36]
спасибо, так я и сделаю


 
Rouse_ ©   (2006-02-01 17:28) [38]


> а как я узнаю какой из них нужный
> может он занят и освободится через час

Флаг состояния держать :)


> к тому же их может потребоваться больше одного за раз

за раз не получиться, только по очереди :)


 
Набережных С. ©   (2006-02-01 17:33) [39]


> Polevi ©   (01.02.06 15:57) [25]

Я бы посоветовал для такой задачи использовать Completion Port. Во первых, он использует как раз LIFO, во вторых использует эффективный алгоритм управления количеством активных потоков.

И по поводу алгоритма. Лучше, ИМХО, периодически, ну скажем, раз в 30 секунд проверять три параметра - средняя загрузка процессоров, количество активных потоков и количество ожидающих потоков. И где-нибудь раз в 3-5 минут корректировать при необходимости количество потоков в пуле. Желательно также накапливать и учитывать при этом кое-какую статистику по распределению нагрузки в течении суток.

Кстати, пример возможного варианта реализации пула с использованием порта завершения есть вот здесь: http://kladovka.net.ru/index.cgi?pid=board&rid=298, но собственно пул - дело несложное. Правда, механизма оптимизации там нет, так как его вряд ли можно сделать универсальным, оторванным от конкретной ситуации.


 
Набережных С. ©   (2006-02-01 17:39) [40]


> Лучше, ИМХО, периодически, ну скажем, раз в 30 секунд проверять
> три параметра

Тем более, что в большинстве случаев нет никакого смысла держать 100 активных потоков на одном процессоре.



Страницы: 1 2 вся ветка

Текущий архив: 2006.04.23;
Скачать: CL | DM;

Наверх




Память: 0.59 MB
Время: 0.077 c
2-1144256054
Nick_serov
2006-04-05 20:54
2006.04.23
Иконки для программы!!!!!!


1-1142502896
КаПиБаРа
2006-03-16 12:54
2006.04.23
Как сделать Абстрактный property


3-1141126420
RomanH
2006-02-28 14:33
2006.04.23
Классификатор адресов России


3-1140965468
Winni
2006-02-26 17:51
2006.04.23
физическое удаление записей из БД Paradox ( файлы *.mb)


3-1141056218
Sollo
2006-02-27 19:03
2006.04.23
dbexpress нужна временная таблица ?