Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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.58 MB
Время: 0.018 c
2-1144400767
dera
2006-04-07 13:06
2006.04.23
Чем можна заменить?


15-1143653618
Kolan
2006-03-29 21:33
2006.04.23
Совместимось bpl пакетов Delphi 2006 с Delphi 7.


15-1142582621
default
2006-03-17 11:03
2006.04.23
Пятничная задачка


4-1138915613
den_c
2006-02-03 00:26
2006.04.23
Язык системы.


11-1125182052
ebta
2005-08-28 02:34
2006.04.23
just a little bug v2.10





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский