LINUX.ORG.RU

Конкурирующая очередь в thread C++

 ,


0

2

Продолжаю мучить сообщество своими хлупыми вопросами на похожие темы ) Вернуть результат thread в С++ без мутексов?

Необходимо запараллелить 3 потока

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

В однопоточной реализации вариантов 1+3 или 1+2 все работает вроде эффективно, задача 1 выполняется менее 30 мс, 2 - от 30 до 100мс, 3 - в районе 50мс

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

В предыдущей теме меня пнули в сторону атомиков, из чтения всяких хабров я понял следующее - работающие только с памятью атомик существенно быстрее, чем системный вызов мьютекса/семафора, однако как я понял в этом случае предлагается ждать в бесконечном цикле изменение атомика - но ведь это загрузит поток на 100%, а у меня только поток 2 грузит оставшиеся 300% на 4х ядрах

При этом как бы еще решить проблему конкуренции за ПОСЛЕДНИЙ кадр, все что раньше попало в очередь уже не имеет значения и просто считаю дропнутым

ЗЫ. Извините за многобукав! ЗЫ1. хотелось бы понять направление в которое двигаться.

★★★

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

Тогда с чем вы не согласны то? Я спросил как проверить не блокируя основной поток, вы привели пример как блокировать «на какой-то совсем короткий интервал времени», при этом вам видимо не ведомо, что sem_trywait эффективнее, да что на меня тупого обращать внимание, продолжайте игнорировать.

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

Я спросил как проверить не блокируя основной поток, вы привели пример как блокировать «на какой-то совсем короткий интервал времени»

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

future_status
wait_for(const chrono::duration<_Rep, _Period>& __rel)
{
  // First, check if the future has been made ready.  Use acquire MO
  // to synchronize with the thread that made it ready.
  if (_M_status._M_load(memory_order_acquire) == _Status::__ready)
    return future_status::ready;

  if (_M_is_deferred_future())
    return future_status::deferred;

  // Don't wait unless the relative time is greater than zero.
  if (__rel > __rel.zero()
      && _M_status._M_load_when_equal_for(_Status::__ready,
					  memory_order_acquire,
					  __rel))
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2100.  timed waiting functions must also join
      // This call is a no-op by default except on an async future,
      // in which case the async thread is joined.  It's also not a
      // no-op for a deferred future, but such a future will never
      // reach this point because it returns future_status::deferred
      // instead of waiting for the future to become ready (see
      // above).  Async futures synchronize in this call, so we need
      // no further synchronization here.
      _M_complete_async();

      return future_status::ready;
    }
  return future_status::timeout;
}
ox55ff ★★★★★
()
Последнее исправление: ox55ff (всего исправлений: 1)
Ответ на: комментарий от ox55ff

виноват, в силу своей тупости не знал, что «какой-то совсем короткий интервал времени» это ноль

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

Тогда с чем вы не согласны то?

Для тупых: я попросил точную цитату с моим утверждением что «вайт по времени это не блокировка». Она у вас есть? Если да, то предъявите. Если нет, то надо что-то делать, не находите?

Я спросил как проверить не блокируя основной поток, вы привели пример как блокировать «на какой-то совсем короткий интервал времени»

Ноль – это тоже совсем короткий интервал времени. Если вы вообще не хотите ждать (а из условия вашей задачи это лично мне было не понятно), то можно задать 0 в качестве значения для wait_for и получить статус future здесь и сейчас. Ваш поток заблокируется только на время проверки статуса и все. В зависимости от реализации это может быть сравнимо с чтением атомика.

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

да я вообще ничего лично от вас не хочу, с вашим нулем, который «интервал времени», может-не может, вы же меня игнорируете, меня это вполне устраивает

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

Лично я в той теме подумал, что для тебя блокировка - это когда поток блокируется до тех пор пока не получит результат от фьючи. С маленьким временем ожидания этого не произойдёт. Поток разблокируется через указанное время даже если ещё нет результата.

Что для тебя есть блокировка? Когда ты в цикле крутишься и ждёшь изменения значения атомарное переменной (spinlock) это по-твоему не блокировка?

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

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

да ту тему уже через семафоры нормально решил, sem_trywait меня вполне устроил, спасибо за уточнение, даже стало теперь интересно как реализовано в sem_trywait ))

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

да я вообще ничего лично от вас не хочу

Для совсем тупых: вы высказали в мой адрес абсурдное обвинение, мол я «заявлял что вайт по времени это не блокировка».

Так что теперь я от вас лично хочу: подтвердите это свое обвинение точной цитатой.

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

2 раза уже процитировал вашу ахинею про ноль и интервал времени, дальше буду сам вас игнорировать.

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

конечно же не пофег, от того что каждый кадр имеет временную метку не означает равномерное воспроизведение

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

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

Нахрена тебе равномерность нагрузки? Что это ещё за нахрен метрика такая, что она даёт? Реальные метрики это объём данных переданных во флешку и объём записи в NAND. Они разные из-за write amplification, хотя контроллер должен эту разницу нивелировать по возможности. Обе метрики минимизируются когда ты пишешь возможно большими пачками. Писать маленькими кусочками с большими интервалами - это самый плохой случай.

запись же делается через stdio.h, которая помимо кеша ОС имеет и свой выровненный кеш по размеру сектора (поскольку запись выполняется по кругу на «сырой» диск), а значит абсолютно без разницы по кадру пишется в кеш или пачкой.

Ну то есть на диск ты и так пишешь пачками. И к чему тогда вообще этот бред про равномерную запись?

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

копирование памяти однозначно снижает производительность

Не снижает, копирование 200 Кб происходит очень быстро.

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

Можно и без копирования, если сетевой поток будет передавать кадр дисковому последовательно.

да ее у меня всего то 512Мб (при 200Кб на кадр)

Итого у тебя общий объём всех очередей будет на 2 500 кадров. За такой объём ты сможешь на лету втыкать новую флешку при заполнении старой, или делать отмотку назад на 1 минуту видео.

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

Это не время. Это нисколько, о чём тебе сказали. Если бы для тебя это было бы время - ты бы не писал подобный мусор. Поэтому не фантазируй.

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

Всё твои 10 фпс, 30 фпс и даже 100фпс - это нисколько.

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

Рассказы твои про вектор не имеют смысла. Ты не можешь чётко сформулировать задачу. Мне лень за тебя что-то придумывать, особенно когда ты что-то навязываешь.

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

с какой частотой поступают новые блоки. Раз в сколько мс.

решил таки я провести как тут советуют «профилирование», но до написание по этим же советам говнокода, оказалось что если просто читать с камеры и не делать ничего вообще, то это занимает в среднем 40 мс!!! Значит время чтения + декодирования я могу как минимум уменьшить на 30-40% просто выполняя это самое декодирование в отдельном потоке, которое само по себе должно занимать для mjpeg в разрешении 1920x1080 порядка 50-60 мс, тем самым еще подняв фпс онлайн видео…

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

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

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

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

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

Зачем копировать ро-память? Чтобы что?

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

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

raspopov
()
Последнее исправление: raspopov (всего исправлений: 1)

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

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

И к чему тогда вообще этот бред про равномерную запись?

дебажу реализацию своей хитрой очереди Конкурирующая очередь в thread C++ (код)

и выяснилось, что запись на флешку кадра у меня занимает 1.5-2 мс где то, при этом кадры я могу считать с камеры либой ффмпега не чаще чем почти через 40 мс (хотя 30 фпс камера отдает) - вот в том числе и по этому мне нужна равномерность потока записи - выровнял частоту потока записи до 67 мс (15фпс), может до 100 мс подниму если плавность картинки устроит.

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

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

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

вот в том числе и по этому мне нужна равномерность потока записи

Не понятно зачем это нужно. Для синхронизации воспроизведения видео нужны метки времени для кадров. Так делают все (не придирайся) контейнеры для видео.

выровнял частоту потока записи до 67 мс

Это всё может сломаться, если загрузка на ЦП по какой-то причине подскочит и запись не уложится в твои тайминги.

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

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

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

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

запись у меня выполняется на сырой носитель тупо условно на /dev/sda по кругу, а большие пачки ограничены скудным размером встроенной оперативы в 512 Мб, где запись хоть и важная, но второстепенная задача

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

запись у меня выполняется на сырой носитель тупо условно на /dev/sda по кругу

И что? От этого он лентой не становится и смысла писать на него через равномерные промежутки времени не появляется.

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

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

slovazap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.