LINUX.ORG.RU

Как опрашивать датчик очень быстро и успевать писать данные в файл ?

 , , ,


3

2

Прога на borland c++ опрашивает датчик каждые 3 мс, накапливает данные в большой буфер, буфер memory mapped на файл и когда наполняется, прога делает сброс на диск. Периодически сброс на диск происходит 100-300 мс, вместо приемлых 1-2 мс. Происходит из-за этого подвисание опроса и пропускаем данные с датчика в те 100-300 мс, потраченные на сброс. Как бы лучше реализовать это ? Сейчас сброс на диск и опрос идут в одном потоке, у потока приоритет наивысший. Получится ли решить проблему, если сброс на диск делать в низкоприоритетном потоке ? Важно, чтобы пока идет сброс длительный, поток опроса продолжал работу. И как можно исправить эту проблему видимо с хардом ?

Получится ли решить проблему, если сброс на диск делать в низкоприоритетном потоке ?

Не знаю точно про винду, но на линуксе это можно делать в потоке с любым приоритетом - если он заблочится на I/O, активны будут только те потоки, которым есть чего делать

annulen ★★★★★ ()

что за датчик, чем подсоединён, в качестве стореджа именно жёсткий диск, который с блинами и крутится? На чём это вообще всё запущено? Что мешает сохранять чаще? Какой размер буфера?

Harald ★★★★★ ()

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

int Buf1[1000],Buf2[1000];

int *current = &Buf1;
int *for_save = &Buf2;

Пишешь в current, как только переполнился - обмениваешь значения current и for_save, и запускаешь сброс for_save на диск.

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

alysnix ()

Linux тут при чем? Или у тебя откомпиленный через borland c++ код под вайном запускается и опрашивает датчик? Про MSVC тут тоже так спрашивать можно теперь?

SZT ★★★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от Harald

Датчик по usb опрашивают, снимают большие массивы данных с него, крутится все на убогом компе с pentium и 2 гиг оперативы у заказчика. Размер буфера максимально большой, чтобы реже писать на диск.

user2132 ()
Ответ на: комментарий от user2132

а зачем писать на диск реже, когда можно писать чаще

какой поток данных с датчика и какая пропускная способность у диска? Если второе меньше, то все усилия тщетны :)

Harald ★★★★★ ()

По теме - делаешь два буфера, когда один из них забивается данными, сразу перескакиваешь на заполнение другого буфера и пинаешь другой специальный тред, который пусть только что заполненный буфер в файл записывает. IPC механизмы в винде точно какие-то есть, можно через мьютекс тупо. В винде вот какие-то критические секции есть https://docs.microsoft.com/en-us/windows/win32/sync/using-critical-section-ob...

Ну или можно семафор, в винапи он тоже есть

SZT ★★★★ ()
Последнее исправление: SZT (всего исправлений: 2)
Ответ на: комментарий от user2132

Датчик по usb опрашивают, снимают большие массивы данных с него, крутится все на убогом компе с pentium и 2 гиг оперативы у заказчика. Размер буфера максимально большой, чтобы реже писать на диск.

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

если данных больше чем он успевает писать, ты вообще проблему не решишь.

alysnix ()
Ответ на: комментарий от user2132

вариант кроме способа набить десяток буферов

Не блокирующий кольцевой буфер, два треда. Один пишет в буфер данные с датчика по кругу, второй оттуда сбрасывает данные на диск, по мере возможности.

anonymous ()
Ответ на: комментарий от anonymous

Не блокирующий кольцевой буфер, два треда. Один пишет в буфер данные с датчика по кругу, второй оттуда сбрасывает данные на диск, по мере возможности.

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

alysnix ()
Ответ на: комментарий от alysnix

будет будиться по каждому байту в кольцевом буфере

это с какой же радости?

сигналит записывающему треду, что надо блок писать

С какой радости №2? Он что, зная, что данные поступают в буфер с определенной скоростью не может прикинуть время, сколько ему еще поспать, если он проснулся, а блок не готов?

anonymous ()
Ответ на: комментарий от lovesan

Я думаю ТС ещё и зарабатывает раз в 15 больше чем все отписавшиеся в треде. На дельфи точно ребята в провинции пишут за те деньги, которые олимпиадникам из яндекса даже и не снились.

pon4ik ★★★★★ ()

Нужно писать в кольцевой страничный буфер в шаренной памяти между двумя процессами. Один процесс наполняет начало кольца, другой - пишет страничками с конца.

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

anonymous ()
Ответ на: комментарий от anonymous

Нужно писать в кольцевой страничный буфер в шаренной памяти между двумя процессами. Один процесс наполняет начало кольца, другой - пишет страничками с конца.

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

alysnix ()
Ответ на: удаленный комментарий

ты ему еще посоветуй еще через гигабит эзернет прокидывать буфер от одного процесса к другому. хехе.

чтобы скинуть на диск. хехе.

один процесс!!! читает датчик, другой процесс!!! на диск пишет. может ему сразу кластер поставить и сисадмина нанять?

alysnix ()

Выкинуть всё нахрен включая с++ setbuff(stdout,NULL); и писать в цикле обычным сразу данные как только они опрошены обычными fprintf()/write().

буфер memory mapped на файл и когда наполняется, прога делает сброс на диск.

В том может и проблема, копите гиг и скидываете его. Ясен пень будет блокировка и просранные тайминги.

LINUX-ORG-RU ()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от alysnix

Ты прикинь, а у нас на работе именно многопроцессное приложение работает уже много лет. Один процесс опрашивает датчики (отдельный процесс на каждый тип датчика) и пишет в общую память, другой процесс пересылает эти значения по сети на другие компы, третий - анализирует значения и логи пишет, четвертый - пишет в БД. Вообщем приложение запускает около 30 процессов. И работа любого процесса независит от работы остальных и каждый процесс можно независимо перезапустить (например, поменяв конфиг-файл). Плюс еще каждый управляющий комп имеет горячий резерв.

sigurd ★★★ ()
Последнее исправление: sigurd (всего исправлений: 1)
Ответ на: комментарий от sigurd

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

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

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

alysnix ()
Ответ на: комментарий от user2132

Программные пути уже подсказали. Два буфера. Пока один записывается, второй скидывается на жесткий диск другим тредом. Или тебе надо чтобы тебе готовый код написали? В чем вопрос вообще?

SZT ★★★★ ()
Ответ на: комментарий от SZT

Мне нужно, чтобы когда 2 поток будет скидывать данные на диск, его выполнение прерывалось 1-ым потоком для опроса датчика. Как это сделать ? Достаточно выставить 2-ому потоку низкий приоритет ? Не будет ли 1 поток в моменты сброса просаживать ? Также интересен вариант 2 процесса и разделяемая память. Можете пояснить про этот вариант, почему он будет хуже или лучше.

user2132 ()
Последнее исправление: user2132 (всего исправлений: 2)
Ответ на: комментарий от user2132

Мне нужно, чтобы когда 2 поток будет скидывать данные на диск, его выполнение прерывалось 1-ым потоком для опроса датчика.

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

если пассивный то правильно так:

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

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

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

зачем потоку2 таймаут на ожидании? потому что если поток1 остановить, то поток 2 будет ждать данных бесконечно. вот чтобы это не происходило, поток2 встает на большой таймаут(гарантировано больше чем периоды его пробуждения потоком1), например если поток1 пробуждает поток2 раз в секунду, то таймаут например 10 секунд. то есть если поток2 сошел с ожидания по таймауту - это ситуация обрабатывается как факт, что поток1 застрял или умер. тут можно или завершать поток2, или давать на консоль диагностику - «поток1 не проявляет активности!!!»

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

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

alysnix ()
Ответ на: комментарий от user2132

Мне нужно, чтобы когда 2 поток будет скидывать данные на диск, его выполнение прерывалось 1-ым потоком для опроса датчика.

Чего? Сам-то подумай, если у тебя так много данных с датчика идет, то поток 2 просто будет постоянно заблокирован в такой схеме. Это раз.

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

Еще один хинт: если ты пишешь на диск, а не в tmpfs какую-нибудь, то тебе лучше писать не часто и по несколько байтов, а редко и большими порциями.

Siborgium ()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от user2132

Бюджетная организация, не дадут)

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

alysnix ()
Ответ на: комментарий от alysnix

Молотит, наполняет буфер и делает сброс, эта схема успешно работает, сброс выполняется за 1 мс, но иногда какие-то просаживания идут и сброс на 100 мс занимает. У нас эмуляторы железа, у заказчика реал оборудование. Проблемы на реал оборудовании идут.

user2132 ()
Ответ на: комментарий от user2132

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

Двухядерные пентиумы бывают: https://en.wikipedia.org/wiki/Pentium#Pentium_Dual-Core_2

Einstok_Fair ★★★ ()
Последнее исправление: Einstok_Fair (всего исправлений: 1)
Ответ на: комментарий от Einstok_Fair

читать одним ядром, писать другим ядром

А вот это интереснее, на машине core 2 duo стоит. Мне нужно в коде что-то указывать или ось сама распихает 2 треда по ядрам. Типа можно ли именно распараллелить эти 2 потока на ядра, чтобы они исполнялись одновременно ?

user2132 ()
Ответ на: комментарий от user2132

Молотит, наполняет буфер и делает сброс, эта схема успешно работает, сброс выполняется за 1 мс, но иногда какие-то просаживания идут и сброс на 100 мс занимает. У нас эмуляторы железа, у заказчика реал оборудование. Проблемы на реал оборудовании идут.

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

  2. сколько ядер на компе клиента

  3. что за диск на компе клиента.

  4. ОПЯТЬ! сколько байт данных считывается в секунду?

alysnix ()
Ответ на: комментарий от alysnix

ось сама распихает треды на два ядра, если не тупая.

Можно гвоздями прибить, чтобы наверняка.
https://en.wikipedia.org/wiki/Processor_affinity

On Linux, the CPU affinity of a process can be altered with the taskset(1) program[2] and the sched_setaffinity(2) system call. The affinity of a thread can be altered with one of the library functions: pthread_setaffinity_np(3) or pthread_attr_setaffinity_np(3).

Einstok_Fair ★★★ ()