Помогите придумать алгоритм пинга

pitrik2

дано: функция sendPing которая посылает пинг внешней системе через каждое время pingInterval после последнего пинга(понга)
метод pongReceived который вызовется в другом потоке когда придет понг от внешней системе
метод check который вызывается в отдельном потоке неизвестно когда и должен мгновенно ответить жива ли внешняя система, система жива если понг пришел в течении времени pongInterval
у пингов еще есть ping_id - который задаем мы и который внешняя система нам возвращает в pong
все эти три функции/потока должны быть грамотно синхронизированы, чтобы все работало при маленьких и близких pingInterval и pongInterval

kruzer25

Я тут что-то не пойму, но если у тебя пинг-понги идут постоянно, то зачем вообще нужны пинги? Почему нельзя обойтись одними лишь понгами?
pongReceived сохраняет в какой-то Singleton время получения последнего понга; check лезет в этот же синглтон и смотрит, приходил ли за последние N секунд понг.

vall

система жива если понг пришел в течении времени pongInterval
пришёл хотябы один ответ за интервал предшествующий текущему моменту или последний пинг вернулся быстрее чем за этот интервал?

katrin2201

второй вариант

while(true) {
state = check;
pingTime = curTime;
sendPing;
}

pongReceived {
pongTime = curTime;
}

boolean check {
if(pingTime > pongTime) {
if(curTime - pingTime < pongInterval) {
return state;
}
return false;
}
return pongTime - pingTime < pongInterval;
}
Засинхронизировать например так: на pingTime, pongTime и state один лок, переваривающий много читателей много писателей.

pitrik2

понги приходят токо на запрос о пинге
пинги нужно рассылать через определенный интервал
понг должен прити в определенное время - если опоздал значит система считается недоступной

kruzer25

понги приходят токо на запрос о пинге
Я так понимаю, понги отправляет тоже твоя система? Тогда пусть пинг запускает отправку назад не одного понга, а одного понга в каждый заданный интервал - запустишь только один пинг при инициализации.
понг должен прити в определенное время
Конкретнее.

kruzer25

Выглядит, как большой кусок говна.
ЗЫ: Обосновать не могу :(

pitrik2

if(curTime - pingTime < pongInterval) {
return state;
}
это ненадежно и фиг засинхронишь такое

pitrik2

Я так понимаю, понги отправляет тоже твоя система?
нет конечно
я про ту систему знаю только что на каждый мой пинг она отправляет назад понг
причем понгов может быть гораздо больше - шина общая и ктото другой может пинг послать и прилетит общий понг
а ping_id могут и пересечься

vall

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

pitrik2

пришёл хотябы один ответ за интервал предшествующий текущему моменту или последний пинг вернулся быстрее чем за этот интервал?
не понял твой вопрос :(
выглядит както так
пингтайм=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

vall

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

katrin2201

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

katrin2201

перекрыться еще может pingSend с pongReceived
получается много писателей будут хотеть циклически писать в один массив
ну можно такое устроить без локов, только смысла не вижу. на узкое место в системе это совсем непохоже.

vall

перекрыться еще может pingSend с pongReceived
это не страшно, в моём алгоритме ping пишет в один массив, а pong только читает оттуда и обновляет статистику.
если pong приходит чёти куда можно либо сделать результат монотонным с помощью cmov или залочить его.
ещё можно сделать переменные для результата персонально на каждое место где может исполняться pong и на check брать максимум из всех, так что lockless можно сделать совсем без изврата =)

Maurog

1) правильно ли я понимаю, что имеется выделенный поток, в котором постоянно шлются пинги?
2) о каком языке программирования идет речь?
3) насколько портабельно должно быть решение? (например, на х86 C++ слово volatile достаточно сильно помогает избежать использование объектов синхронизации)
4) название топика не очень понятно. нужно правильно синхронизировать или придумать мудрый алгоритм пинга? это две разные задачи :smirk:
мне кажется, что функция check не должна что-либо вычислять, ей просто надо прочитать флажок bool IsSystemAlive, который устанавливается функциями sendPing + pongReceived

pitrik2

1) не понятен вопрос, есть то что я сам напишу, есть другие варианты рассылать пинги как не через выделенный поток?
понг приходит в отдельном потоке, но загнать его в поток пинга проблем же никаких нет (тупо после пинга засыпать, а когда придет понг или истечет время просыпаться)
2) неважно, я же алгоритм спрашиваю, а не готовый код
3) неважно, я же алгоритм спрашиваю, а не готовый код
всякие там локи, волатайлы во всех языках в том или ином виде есть
4) согласен, немного неудачно тему назвал, есть хорошие варианты для переименования?
не очень понимаю какие могут быть варианты пинга :( поясни плиз
> ей просто надо прочитать флажок bool IsSystemAlive, который устанавливается функциями sendPing + pongReceived
не вопрос, хорошее начало некого алгоритма, хочется услышать продолжение :)

Maurog

2) неважно, я же алгоритм спрашиваю, а не готовый код
3) неважно, я же алгоритм спрашиваю, а не готовый код
всякие там локи, волатайлы во всех языках в том или ином виде есть
очень много "не важно". должно быть что-то важно. пытаюсь понять =)
например, присоединяюсь к

pitrik2

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

vall

понг приходит в отдельном потоке, но загнать его в поток пинга проблем же никаких нет (тупо после пинга засыпать, а когда придет понг или истечет время просыпаться)
а какие тогда вообще проблемы с синхронизацией?
она тут просто не нужна.

ppplva

Чем меньше потоков, тем лучше, да. Сэкономишь немного нервных клеток на отладке.

katrin2201

если начинал так же - значит что-то недоговаривается, или баг где-то в другом месте
по поводу вызовов кусков кода в другом порядке
ты на джаве пишешь?
вообще можешь попробовать запостить свои конкретные изыски - может станет понятнее

pitrik2

хе
может ты и прав

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;
}
}
}

вроде то что нужно
что скажете?

pitrik2

очень много "не важно". должно быть что-то важно. пытаюсь понять =)
ну вот смотри, уже три варианта решения задачи привели
с массивом, с проверкой времен, и последний вариант еще проще
изначально собсна я и спрашиал помочь подобрать клевый вариант

Maurog

1)
guard.value = ping_id;
тут надо guard.ping_id ?
2) я вижу рейс с чтением\записью guard.ping_id
3) а доступ к isAlive не требует синхронизации?

pitrik2

1) поправил
2) не понял
3) isAlive волатайлная

Maurog

guard.wait(pongTime);
это выглядит странно. у тебя интервал пинга увеличится и станет pongTime + pingTime.
а вру..нормуль вроде

Maurog

2) не понял
мне кажется, что _перед_ send надо выставить guard.ping_id

ppplva

 guard.signalAll; 

Это conditional variable? Зачем он тут?

Maurog

я не спец в этом языке, но предположил, что это нужно для guard.wait(pongTime); =\
хотя действительно глючно: залочили ресурс и под этим же локом сидим и ждем чего-то ;)

ppplva

Это как раз нормально, почитай про них где-нибудь. Непонятно зачем он вообще используется в задаче, где любая операция может быть выполнена "моментально", то есть без ожидания других.

pitrik2

это выглядит странно. у тебя интервал пинга увеличится и станет pongTime + pingTime.
а вру..нормуль вроде
увеличится
он станет pingTime + min(pongTime, за соклько пришел последний понг)
но вроде так даже более правильно
хз, на это можно забить

pitrik2

мне кажется, что _перед_ send надо выставить guard.ping_id
не вижу в этом смысла
гарда меняем только в засинхроненном блоке
send - операция долгая, ее в засинхроненном блоке делать нельзя

katrin2201

нет, не кажется
лучше все тело цикла вайл засунуть в лок

katrin2201

ну тогда это "ненадежно" будет =)
представь - сенд выполнился, ответ на пинг пришел раньше, чем первый тред успел войти в лок.
в итоге пинг потеряется.

Maurog

Это как раз нормально, почитай про них где-нибудь.
а можно ссылку? ато я тогда не понимаю, что такое lock(guard) =\ я подумал, что два потока не могут сделать такой лок одновременно..только когда один из них выйдет из такого скоупа...

pitrik2

Это 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;
}
}
}

Maurog

ну тогда это "ненадежно" будет =)
представь - сенд выполнился, ответ на пинг пришел раньше, чем первый тред успел войти в лок.
в итоге пинг потеряется.
ага. это и есть рейс.

pitrik2

ну тогда это "ненадежно" будет =)
представь - сенд выполнился, ответ на пинг пришел раньше, чем первый тред успел войти в лок.
в итоге пинг потеряется.
мдя
говно :(

katrin2201

там при входе в guard.wait лок отпускается

pitrik2

только когда один из них выйдет из такого скоупа...
или когда этот один из них "уснет", т.е. станет ожидать остальных
guard.wait(pongTime); - вот тут второй поток "включится"

Maurog

sleep(pingInterval - pongInterval);
как-то брутально. слишком частые пинги могут быть. прежний вариант мне больше нравился =)

Maurog

а..спасибо, воткнул )

pitrik2

я тут еще подумал а может ли быть pingInterval меньше чем pongInterval?
есть в этом смысл или нет?

Maurog

я тут еще подумал а может ли быть pingInterval меньше чем pongInterval?
есть в этом смысл или нет?
есть

pitrik2

лучше все тело цикла вайл засунуть в лок
если будет много понгов и операция ping более менее длинная
то они выстроятся в огромную очередь

pitrik2

ну вот
этот алгоритм улетел в трубу
остался алепаровский и с цикл. массивом

katrin2201

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

Maurog

предлагаю попытаться вернуть его из трубы.
pingInteval как константа может быть меньше pongInterval-a, но реальный sendPing может быть чуток реже, чем pingInterval и зависеть от реального pong-a
зы: не опечатался ли я где-нибудь...вечереет...

pitrik2

если пинги будут рожаться только в том цикле вайл, то никакой очереди не получится
я ж вроде писал уже, что шина общая (или хотел но забыл?)
т.е. пинги рождаются токо у меня, но вот понгов может быть дох и больше
они то и выстроятся в очередь
лочемся, делаем пинг
в это время приходют 50 понгов и встают в очередь на лок
пинг прошел, засыпаем, начинают обрабатываться понги
30 штук обработалось, пошел новый пинг
итого накопилось уже 50+20 = 70 в очереди
конечно такое маловероятно, но вполне возможно

pitrik2

что уж это у тебя будет - несинхренный массив как у блайнда или какой нить Vector - твое дело.
а нужен ли массив то?
надо хранить самый младший ping_id на который еще не пришел понг и время его отправки
если допустим храним 2 и пришел понг на 5, то терь будем хранить 6, понги на 3,4,5 нас уже не интересуют
хотя не, непонятно что делать если понгов не будет...

katrin2201

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

katrin2201

нужен, иначе смысл пингинтервала меньшего чем понгинтервала пропадет
допустим
пингинтервал == 1
понгитервал == 5
теперь последовательность
1. пинг 1
2. пинг 2
3. пинг 3
4. пинг 4
4. понг x
5. пинг 5
...
теперь если икс от 1 до 4 - то система считается живой
а твой алгоритм так или иначе будет во время 4 ждать какого то фиксированного пинга (младшего или старшего не важно)
именно поэтому нужен массив
ну или надо согласиться, что понгинтервал <= пингинтервал, и тогда на массив можно забить

Maurog

ну или надо согласиться, что понгинтервал <= пингинтервал, и тогда на массив можно забить
предлагаю забить )
то есть мы можем себе позволить более частый пинг, только если очень частый понг. если понг редкий, то и пинг должен быть такой же редкий.

NataNata

в одной системе я пошел другим путем. там у меня клиент и сервер друг другу шлют пинги через некоторое время, но без ответа (а не так, что сервер отвечает на пинги клиента)

katrin2201

шлют пинги
heartbeat =)
Оставить комментарий
Имя или ник:
Комментарий: