Форум: "WinAPI";
Текущий архив: 2006.04.23;
Скачать: [xml.tar.bz2];
Вниз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 вся ветка
Форум: "WinAPI";
Текущий архив: 2006.04.23;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.015 c