Re[5]: Swap 2 buffers
От: andrey.desman  
Дата: 09.08.19 08:32
Оценка:
Здравствуйте, Nuzhny, Вы писали:

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

N>Не будем забывать, что это учебная задача. Но всё равно не так уж и странно. Можно представить, что у нас Producer получает на вход картинку, на которой тяжёлая нейросеть пытается найти объекты. Вот мы и запускаем её в отдельном потоке, а пока обрабатываем результаты предыдущего распознавания. Подчеркну, что не стоит акцентировать вопрос на предметной области. Кажется, что такая задача весьма общая и может иметь такое же общее решение. Может быть у неё есть общепринятое название? Я бы с удовольствием загуглил, но не знаю что.

Так или иначе, если какой-то результат нельзя отбросить и/или переиспользовать, то ждать придется.
Пытаться не ждать, когда ждать необходимо, просто не получится.
Re[8]: Swap 2 buffers
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 09.08.19 08:32
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Тут же цикл, где на каждой итерации запускается поток (std::async), а потом синхронно ожидается его заверешение (answer.wait()). Выигрышь по времени тут только из-за параллельно выполняющихся слипов. В принципе, если в цикле вместо слипа делать что-то осознанное, но если ничего не делать, то прямой вызов будет лучше.


Так в реальности что-то и делается. Один поток генерирует результаты, а второй их обрабатывает. Ускорение до двух раз теоретически возможно просто сделав лаг на 1 итерацию.
Re[6]: Swap 2 buffers
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 09.08.19 08:34
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Так или иначе, если какой-то результат нельзя отбросить и/или переиспользовать, то ждать придется.

AD>Пытаться не ждать, когда ждать необходимо, просто не получится.

Да, разумеется, я готов ждать. Ещё раз скажу, что хочется решить всё это на современном С++ более высокоуровневыми средствами.
Re[7]: Swap 2 buffers
От: andrey.desman  
Дата: 09.08.19 08:38
Оценка:
Здравствуйте, Nuzhny, Вы писали:

AD>>Так или иначе, если какой-то результат нельзя отбросить и/или переиспользовать, то ждать придется.

AD>>Пытаться не ждать, когда ждать необходимо, просто не получится.
N>Да, разумеется, я готов ждать. Ещё раз скажу, что хочется решить всё это на современном С++ более высокоуровневыми средствами.

Так или иначе, там будут потоки, мьютексы и условные переменные. В C++ таких очередей нет, так что или где-то на стороне искать надо, или самому делать.
Re[7]: Swap 2 buffers
От: Masterspline  
Дата: 09.08.19 09:33
Оценка:
N> Ещё раз скажу, что хочется решить всё это на современном С++ более высокоуровневыми средствами.

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

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

Возможно, тебе нужно реализовать класс DataGenerator, который в методе run() запустит поток-генератор данных, а в методе get_data() будет возвращать очередной буфер, останавливаясь в ожидании, когда там появятся данные (и передавать освободившийся). Метод stop() будет останавливать поток-генератор. Однозначно, тот код, который ты написал нужно структурировать в классы (я был уверен, что он написан в процедурном стиле, потому что это чисто учебная задача).
Re: Swap 2 buffers
От: astel  
Дата: 11.08.19 22:18
Оценка:
Здравствуйте, Nuzhny, Вы писали:

N>
N>    int buf[2] = { 0 }; // Two buffers
N>    size_t currInd = 0; // Current ready buffer index
N>

А вот такое тупое решение не подойдет?
 int buf[2] = { 0 }; 
 atomic<size_t>  currInd=0;

 // потом когда надо переключить буфер
 currInd.exchange(1-currInd);
Re[2]: Swap 2 buffers
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 16.08.19 07:58
Оценка:
Здравствуйте, astel, Вы писали:

A>А вот такое тупое решение не подойдет?

A>
A> int buf[2] = { 0 }; 
A> atomic<size_t>  currInd=0;

A> // потом когда надо переключить буфер
A> currInd.exchange(1-currInd);
A>


Вот, кстати, я в своёс старом коде погонял разные сценарии и нашёл гонку в этом месте при переключении буфера. По итогу, оказалось очень классным решение Masterspline с двумя независимыми счётчиками в каждом потоке: они и работают верно, и синхронизации не требуют.
Re: Swap 2 buffers
От: Molchalnik  
Дата: 08.11.19 23:03
Оценка:
Здравствуйте, Nuzhny, Вы писали:

N>Приветствую!

N>Хочу разобраться с тем, как сделать работу с двумя буферами на С++ без явного использования мьютексов в качестве упражнения. Реальный прототип — это два изображения, а не целые числа, с двумя мьютексами и условными переменными у меня работает, но хочется сделать это проще, быстрее и посовременней.

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

Доступ к первому буферу — Buffers[index], к второму — Buffers[!index]

а ещё лучше — сделай массив на три volatile (или atomic) указателя на Buffer. и в них размести первый — второй — первый. Тогда Buffers[index+1] всегда будет второй буфер. Это лучше, потому что Buffers[!index] неатомарная операция, а Buffers[index+1] атомарна при переводе в асм. Только нужно смотреть на барьеры памяти.

а если надо свапнуть — с помощью атомарной функции заменяешь index на !index;

а если уж свапать без lock-free, то на спинлоках, а не на мьютексах. это же короткая операция — три присвоения укзаателя. мьютекс на мелких операциях расточителен, имхо.
Re[3]: Swap 2 buffers
От: Nikе Россия  
Дата: 10.11.19 13:46
Оценка:
Здравствуйте, Nuzhny, Вы писали:

N>Как обычно в этих случаях и работает: в один буфер пишем со звуковой карты, а другой слушаем — потом меняем, в один буфер рисуем, а другой выводим на экран — потом меняем. Приём старый, решается мьютексами и condition variable, а мне интересно без них.


Так-то зачастую тремя, первый выводится, в два другие рендерятся (чтобы не ждать, пока первый станет доступный для заполнения). А ещё всё активнее проникают технологии типа variable refresh rate, которые, при должном стечении обстоятельств позволяют одним обходиться, а то и просто рабочим кешем.
Нужно разобрать угил.
Отредактировано 10.11.2019 13:56 Nikе . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.