Помогите придумать алгоритм пинга
pongReceived сохраняет в какой-то Singleton время получения последнего понга; check лезет в этот же синглтон и смотрит, приходил ли за последние N секунд понг.
система жива если понг пришел в течении времени pongIntervalпришёл хотябы один ответ за интервал предшествующий текущему моменту или последний пинг вернулся быстрее чем за этот интервал?
while(true) {
state = check;
pingTime = curTime;
sendPing;
}
pongReceived {
pongTime = curTime;
}
Засинхронизировать например так: на pingTime, pongTime и state один лок, переваривающий много читателей много писателей.
boolean check {
if(pingTime > pongTime) {
if(curTime - pingTime < pongInterval) {
return state;
}
return false;
}
return pongTime - pingTime < pongInterval;
}
пинги нужно рассылать через определенный интервал
понг должен прити в определенное время - если опоздал значит система считается недоступной
понги приходят токо на запрос о пингеЯ так понимаю, понги отправляет тоже твоя система? Тогда пусть пинг запускает отправку назад не одного понга, а одного понга в каждый заданный интервал - запустишь только один пинг при инициализации.
понг должен прити в определенное времяКонкретнее.
ЗЫ: Обосновать не могу
if(curTime - pingTime < pongInterval) {это ненадежно и фиг засинхронишь такое
return state;
}
Я так понимаю, понги отправляет тоже твоя система?нет конечно
я про ту систему знаю только что на каждый мой пинг она отправляет назад понг
причем понгов может быть гораздо больше - шина общая и ктото другой может пинг послать и прилетит общий понг
а ping_id могут и пересечься
небольшой циклически заполняемый массив с последними пингами, адресуемый по айдишкам, и тайм стэмп последнего успешного пинга на выходе.
если конечно запись времени атомарна.
пришёл хотябы один ответ за интервал предшествующий текущему моменту или последний пинг вернулся быстрее чем за этот интервал?не понял твой вопрос
выглядит както так
пингтайм=10
понгтайм=5
в первом столбике время
0. ping 1
1. check=false
2. pong 1
3. check=true
10. ping 2
11. check=true
14. check=true
16. check=false
17. pong 2
18. check=false
20. ping 3
21. check=false
22. pong 2
23. check=false
24. pong 3
25. check=true
ну в общем да, если несколько pongReceived не перекрываются или есть атомарный cmov можно сделать без локов.
это ненадежно и фиг засинхронишь такоезасинхронить такое проблемы никакой нету абсолютно.
а вот что ты понимаешь под ненадежно - непонятно.
получается много писателей будут хотеть циклически писать в один массив
ну можно такое устроить без локов, только смысла не вижу. на узкое место в системе это совсем непохоже.
перекрыться еще может pingSend с pongReceivedэто не страшно, в моём алгоритме ping пишет в один массив, а pong только читает оттуда и обновляет статистику.
если pong приходит чёти куда можно либо сделать результат монотонным с помощью cmov или залочить его.
ещё можно сделать переменные для результата персонально на каждое место где может исполняться pong и на check брать максимум из всех, так что lockless можно сделать совсем без изврата =)
2) о каком языке программирования идет речь?
3) насколько портабельно должно быть решение? (например, на х86 C++ слово volatile достаточно сильно помогает избежать использование объектов синхронизации)
4) название топика не очень понятно. нужно правильно синхронизировать или придумать мудрый алгоритм пинга? это две разные задачи
мне кажется, что функция check не должна что-либо вычислять, ей просто надо прочитать флажок bool IsSystemAlive, который устанавливается функциями sendPing + pongReceived
понг приходит в отдельном потоке, но загнать его в поток пинга проблем же никаких нет (тупо после пинга засыпать, а когда придет понг или истечет время просыпаться)
2) неважно, я же алгоритм спрашиваю, а не готовый код
3) неважно, я же алгоритм спрашиваю, а не готовый код
всякие там локи, волатайлы во всех языках в том или ином виде есть
4) согласен, немного неудачно тему назвал, есть хорошие варианты для переименования?
не очень понимаю какие могут быть варианты пинга поясни плиз
> ей просто надо прочитать флажок bool IsSystemAlive, который устанавливается функциями sendPing + pongReceived
не вопрос, хорошее начало некого алгоритма, хочется услышать продолжение
2) неважно, я же алгоритм спрашиваю, а не готовый кодочень много "не важно". должно быть что-то важно. пытаюсь понять =)
3) неважно, я же алгоритм спрашиваю, а не готовый код
всякие там локи, волатайлы во всех языках в том или ином виде есть
например, присоединяюсь к
засинхронить такое проблемы никакой нету абсолютно.надежно - ну как объяснить, значит что это просто работает
а вот что ты понимаешь под ненадежно - непонятно.
т.е. не случается раз в месяц что "не повезло" и какойто кусок кода вызвался не в том порядке и все поломалось
попробую твою штуку переписать завтра по новой
то что у мя щас как то дико выглядит, а начинал я вроде также
понг приходит в отдельном потоке, но загнать его в поток пинга проблем же никаких нет (тупо после пинга засыпать, а когда придет понг или истечет время просыпаться)а какие тогда вообще проблемы с синхронизацией?
она тут просто не нужна.
Чем меньше потоков, тем лучше, да. Сэкономишь немного нервных клеток на отладке.
по поводу вызовов кусков кода в другом порядке
ты на джаве пишешь?
вообще можешь попробовать запостить свои конкретные изыски - может станет понятнее
может ты и прав
check {
return isAlive;
}
sendPing {
while(true) {
ping_id++;
send(ping_id);
lock(guard) {
guard.received = false;
guard.ping_id = ping_id;
guard.wait(pongTime);
isAlive = guard.received;
guard.ping_id = -1;
}
sleep(pingInterval);
}
}
pongReceived(ping_id) {
lock(guard) {
if(guard.ping_id == ping_id) {
guard.received = true;
guard.signalAll;
}
}
}
вроде то что нужно
что скажете?
очень много "не важно". должно быть что-то важно. пытаюсь понять =)ну вот смотри, уже три варианта решения задачи привели
с массивом, с проверкой времен, и последний вариант еще проще
изначально собсна я и спрашиал помочь подобрать клевый вариант
guard.value = ping_id;тут надо guard.ping_id ?
2) я вижу рейс с чтением\записью guard.ping_id
3) а доступ к isAlive не требует синхронизации?
2) не понял
3) isAlive волатайлная
guard.wait(pongTime);это выглядит странно. у тебя интервал пинга увеличится и станет pongTime + pingTime.
а вру..нормуль вроде
2) не понялмне кажется, что _перед_ send надо выставить guard.ping_id
guard.signalAll;
Это conditional variable? Зачем он тут?
хотя действительно глючно: залочили ресурс и под этим же локом сидим и ждем чего-то
Это как раз нормально, почитай про них где-нибудь. Непонятно зачем он вообще используется в задаче, где любая операция может быть выполнена "моментально", то есть без ожидания других.
это выглядит странно. у тебя интервал пинга увеличится и станет pongTime + pingTime.увеличится
а вру..нормуль вроде
он станет pingTime + min(pongTime, за соклько пришел последний понг)
но вроде так даже более правильно
хз, на это можно забить
мне кажется, что _перед_ send надо выставить guard.ping_idне вижу в этом смысла
гарда меняем только в засинхроненном блоке
send - операция долгая, ее в засинхроненном блоке делать нельзя
лучше все тело цикла вайл засунуть в лок
представь - сенд выполнился, ответ на пинг пришел раньше, чем первый тред успел войти в лок.
в итоге пинг потеряется.
Это как раз нормально, почитай про них где-нибудь.а можно ссылку? ато я тогда не понимаю, что такое lock(guard) =\ я подумал, что два потока не могут сделать такой лок одновременно..только когда один из них выйдет из такого скоупа...
Это conditional variable? Зачем он тут?ну как
раз понг получен то зачем его продолжать ожидать?
хотя возможно так даже лучше будет
добавил "pingInterval - pongInterval" во второй вэйт
и пинги равномерно будут слаться с
check {
return isAlive;
}
sendPing {
while(true) {
ping_id++;
send(ping_id);
lock(guard) {
guard.received = false;
guard.ping_id = ping_id;
guard.wait(pongInterval);
isAlive = guard.received;
guard.ping_id = -1;
}
sleep(pingInterval - pongInterval);
}
}
pongReceived(ping_id) {
lock(guard) {
if(guard.ping_id == ping_id) {
guard.received = true;
}
}
}
ну тогда это "ненадежно" будет =)ага. это и есть рейс.
представь - сенд выполнился, ответ на пинг пришел раньше, чем первый тред успел войти в лок.
в итоге пинг потеряется.
ну тогда это "ненадежно" будет =)мдя
представь - сенд выполнился, ответ на пинг пришел раньше, чем первый тред успел войти в лок.
в итоге пинг потеряется.
говно
там при входе в guard.wait лок отпускается
только когда один из них выйдет из такого скоупа...или когда этот один из них "уснет", т.е. станет ожидать остальных
guard.wait(pongTime); - вот тут второй поток "включится"
sleep(pingInterval - pongInterval);как-то брутально. слишком частые пинги могут быть. прежний вариант мне больше нравился =)
а..спасибо, воткнул )
есть в этом смысл или нет?
я тут еще подумал а может ли быть pingInterval меньше чем pongInterval?есть
есть в этом смысл или нет?
лучше все тело цикла вайл засунуть в локесли будет много понгов и операция ping более менее длинная
то они выстроятся в огромную очередь
этот алгоритм улетел в трубу
остался алепаровский и с цикл. массивом
ну про очередь во-первых спорно, если пинги будут рожаться только в том цикле вайл, то никакой очереди не получится
да и в твоем случае эта очередь просто улетит в трубу, никак не обработается
плюс, если интервал пингтайм может быть меньше понгтайм, то в такой постановке задачи прокатит только вариант с хранением всех пингов не старее понгтайма в коллекшене. что уж это у тебя будет - несинхренный массив как у блайнда или какой нить Vector - твое дело.
pingInteval как константа может быть меньше pongInterval-a, но реальный sendPing может быть чуток реже, чем pingInterval и зависеть от реального pong-a
зы: не опечатался ли я где-нибудь...вечереет...
если пинги будут рожаться только в том цикле вайл, то никакой очереди не получитсяя ж вроде писал уже, что шина общая (или хотел но забыл?)
т.е. пинги рождаются токо у меня, но вот понгов может быть дох и больше
они то и выстроятся в очередь
лочемся, делаем пинг
в это время приходют 50 понгов и встают в очередь на лок
пинг прошел, засыпаем, начинают обрабатываться понги
30 штук обработалось, пошел новый пинг
итого накопилось уже 50+20 = 70 в очереди
конечно такое маловероятно, но вполне возможно
что уж это у тебя будет - несинхренный массив как у блайнда или какой нить Vector - твое дело.а нужен ли массив то?
надо хранить самый младший ping_id на который еще не пришел понг и время его отправки
если допустим храним 2 и пришел понг на 5, то терь будем хранить 6, понги на 3,4,5 нас уже не интересуют
хотя не, непонятно что делать если понгов не будет...
лаги начнутся только в случае, если понгов будет больше, чем проц в риалтайме может обработать. вот тогда лаг будет копиьтся.
вообще я не знаю конечно, но по-моему ты чересчур тщательно пытаешься реализовать этот кусок =)
если сильно хочется чтоб сенд не был в локе - сделай его асинхронным
допустим
пингинтервал == 1
понгитервал == 5
теперь последовательность
1. пинг 1
2. пинг 2
3. пинг 3
4. пинг 4
4. понг x
5. пинг 5
...
теперь если икс от 1 до 4 - то система считается живой
а твой алгоритм так или иначе будет во время 4 ждать какого то фиксированного пинга (младшего или старшего не важно)
именно поэтому нужен массив
ну или надо согласиться, что понгинтервал <= пингинтервал, и тогда на массив можно забить
ну или надо согласиться, что понгинтервал <= пингинтервал, и тогда на массив можно забитьпредлагаю забить )
то есть мы можем себе позволить более частый пинг, только если очень частый понг. если понг редкий, то и пинг должен быть такой же редкий.
в одной системе я пошел другим путем. там у меня клиент и сервер друг другу шлют пинги через некоторое время, но без ответа (а не так, что сервер отвечает на пинги клиента)
шлют пингиheartbeat =)
Оставить комментарий
pitrik2
дано: функция sendPing которая посылает пинг внешней системе через каждое время pingInterval после последнего пинга(понга)метод pongReceived который вызовется в другом потоке когда придет понг от внешней системе
метод check который вызывается в отдельном потоке неизвестно когда и должен мгновенно ответить жива ли внешняя система, система жива если понг пришел в течении времени pongInterval
у пингов еще есть ping_id - который задаем мы и который внешняя система нам возвращает в pong
все эти три функции/потока должны быть грамотно синхронизированы, чтобы все работало при маленьких и близких pingInterval и pongInterval