Задать вопрос
  • Какой способ организации чтения и записи файлов в разных форматах оптимальнее?

    @MarkusD Куратор тега C++
    Mercury13 , а тут, понимаешь, какой вопрос, такой и ответ... Размыто всё, конкретики никакой. Структуры бывают разные, программы бывают свои и чужие, форматы - текстовые, бинарные и не только.
    Это просто всё, что мне пришло в голову при чтении вопроса. :)
    Форматы файлов для меня далеко не пустой звук. Подсказать могу многое. Главное - это правильно задать вопрос...

    Ну и мне совершенно не важно, насколько мой ответ решает вопрос в его описании. Мне важно просто поделиться имеющейся информацией и, возможно, подтолкнуть человека к дальнейшей прагматике по вопросу.
  • Как лучше организовать многопоточную архитектуру?

    @MarkusD Куратор тега C++
    Cyapa , да, если будут вопросы, ты можешь или тут их задавать, или оформлять новый вопрос и сразу приглашать меня. :)
    Новый вопрос будет даже лучше, чтобы все люди могли поделиться своими навыками.
  • Как лучше организовать многопоточную архитектуру?

    @MarkusD Куратор тега C++
    А, я уже рисовал себе в уме какую-нибудь гирлянду из десятков устройств на проводах. :)
    Побуду немного теоретиком кайфа и накидаю видение этого подхода.

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

    Что тут есть пул потоков и работники. Пул потоков предоставляет только управление небольшим количеством потоков. Потоки создаются при инициализации пула и живут до его деинициализации. Работник – это цикл обработки задач. Задачи поступают из очередей. Очередь задач помечается некоторым семейством. Вон, если применять асинхронный планировщик таймеров, то для него понадобится свое отдельное семейство и очередь (и эта очередь должна отдавать задачи только для уже сработавших таймеров). Задача всегда планируется для конкретной очереди.
    Для каждого потока из пула потоков создается работник и передается в этот поток. Работнику назначается набор семейств очередей с установленными приоритетами. При наличии задач в очереди, работник забирает не все, уповая на то, что эту очередь обслуживают несколько работников. Обычно из очереди берут не больше N задач. Для очередей характерна синхронизация семафором, т.е. работники просто усыпляются на ожидании задач в случае их отсутствия.
    Но есть еще один работник, чье поведение нехарактерно – это работник главного потока. Он не блокирует свой поток при отсутствии задач и для него определяются свое отдельное от всех семейство и очередь задач. Этот работник выполняет только то, что непременно надо выполнить в главном потоке процесса.
    Каждую задачу можно сопроводить специальным обработчиком, который автоматически планируется в необходимую очередь сразу после завершения задачи. Во время планирования в этот обработчик передается результат выполнения задачи. Во время планирования задачи в ее очередь, к задаче добавляется этот самый обработчик с пометкой его очереди. Это дает возможность саму задачу выполнить асинхронно, а ее результат, например, обработать в главном потоке. Таким же образом можно организовать цепное планирование задач в зависимости от результатов предыдущих задач в цепи. Это очень простая схема проактора, полноценный проактор нам тут и не нужен.

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

    В момент обнаружения нового устройства для него создается актер. Актер устройства планирует себе таймер для проверки живости устройства. В общем смысле это называется ping/heartbeat service. Если подключенное устройство само с некоторым интервалом отсылает сигнал своей живости - это heartbeat, его можно просто читать и обновлять состояние живости. В ином случае надо делать схему ping-pong с интервалом ожидания ответа(pong). Для ping service удобно запланировать два таймера, из которых только один будет включен в одно конкретное время. Ping-таймер отмеряет интервал между отсылкой пинга. Отсылка пинга останавливает Ping-таймер и запускает Pong-таймер. Последний считает интервал ожидания ответа от устройства. Таймеры снова меняются местами в момент получения ответа от устройства или истечения времени Pong-таймера. Именно в этом месте можно реализовать поведение при потере устройства.

    Прием данных с устройства делается тоже по таймеру с маленьким интервалом. По этому таймеру планируется только опрос буфера чтения (эмм... у тебя там сокеты?) на возможность чтения.
    А фактическое чтение выполняется только в случае успеха первой задачи (т.е. если проверка показала что читать можно).
    Это - планирование двух асинхронных увязанных задач (проверка + чтение) с условием, что вторая задача выполнится только если результат первой задачи успешен.
    Callback задачи чтения производит диспетчеризацию принятого буфера с помощью работника основного потока.

    Для клиента устройства актер и будет этим самым устройством. Клиент использует публичный интерфейс актера для общения с устройством. Сам актер, по запросу клиента формирует или одну задачу, или цепочку задач.
    Скажем, надо получить с устройства некоторые данные. У клиента устройства есть хендлер для этих данных. Клиент вызывает функцию актера устройства, передавая туда хендлер. Актер планирует задачи:
    1) послать на устройство запрос данных из потока любого свободного работника (вот тут я не спросил, синхронные ли эти запросы);
    2) вызвать клиентский хендлер с принятыми данными в момент их диспетчеризации.

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

    @MarkusD Куратор тега C++
    Cyapa , дьявол в деталях - это правда. :)
    Смотри, в таком случае мне нужна информация. Ты случайно не IoT-хаб проектируешь?
    Как узнается что в системе появилось еще одно устройство, с которым надо взаимодействовать?
    Как у тебя сейчас сделано, чем именно занимаются потоки для устройств?
    У меня еще рабочее время, разница между нами - 5 часов, а такой объем писанины и сторонней прагматики я смогу себе только после работы позволить. :)
  • Как лучше организовать многопоточную архитектуру?

    @MarkusD Куратор тега C++
    Или тебе прям принципиальную схему описать? :)
  • Как лучше организовать многопоточную архитектуру?

    @MarkusD Куратор тега C++
    Cyapa , да, могу. :)
    https://en.wikipedia.org/wiki/Thread_pool

    Пул потоков в данном случае представлен пулом работников для параллельной обработки задач. Задачей является любой сервис (тик, посылка команды, проверка наличия данных в буфере приема, чтение буфера приема и.т.д) одного конкретного девайса.
    Число работников в пуле фиксировано, никак не связано с числом девайсов и значительно меньше числа подключенных девайсов (2/4/8 работников против 20+ девайсов). Люди любят делать число работников в пуле по числу ядер процессора, крепить работников к отдельным ядрам и типа наслаждаться слабыми коллизиями планирования.
    Помимо работников у тебя еще всегда есть главный поток процесса, который тоже является работником, но выполняет только те задачи, которые нужно выполнить только в главном потоке (например, запуск callback функций после выполнения асинхронных задач).

    Сервисом конкретного устройства занимается один конкретный актер (Actor model). Актер занимается планированием задач сервиса устройства (используя схему Reactor/Proactor). Сервисом устройства можно назвать опрос на предмет потери соединения с устройством, пинг устройства, посылку команд на устройство, проверку ответа от устройства, может что-нибудь еще...
    Актер устройства планирует действие, которое должно быть выполнено асинхронно одним из работников в потоке работника.

    Почему именно Proactor, а не Reactor. Реактор применяется тогда, когда необходимо приостановить работу вызывающего потока на время асинхронной операции. Выглядит это как простой вызов функции. Чтение из файла или сокета в синхронном режиме, для примера.
    Проактор применяется тогда, как есть возможность запланировать некоторые действия в определенной последовательности - поставить callback на исполнение после асинхронной операции.
    Я думаю, Проактор для тебя может оказаться очень удобным.

    Почему я предложил именно такую схему. По описанию я увидел что потоками ты задумал облегчить себе работу. Сделать по потоку на устройство, а внутри потока у тебя типа обычная синхронная программа с синхронным сервисом устройства. Так ведь?
    В любом случае это означает что потоки у тебя большую часть времени спят. Именно в этом случае куда удобнее исправить все на предложенную схему. Плюсом, сервис устройств станет удобнее, особенно если разделишь задачи по пингу/проверке живости устройства с задачами отсылки/проверки наличия/приема данных.
  • Можно ли оптимизировать сортировку?

    В код я не смотрел, поэтому на ответ, а коммент. Однако, по описанию это никакой не circle sort, это quick sort с кривоватой и слабо понятной реализацией. Его можно и переписать более компактно, и эффективность повысить. В коде написаны, прям говоря, страсти...
    algolist.manual.ru/sort/quick_sort.php
  • Как передать в фунцкию пустой аргумент?

    Самый полезный ответ. Похоже ты понял автора лучше всех. Уважаю! :)
  • Число 0, как символ?

    @MarkusD Куратор тега C++
    Airat1995 , на счет шил и мыла тут все просто. Проблема, которую ты встретил и описал в этом вопросе, всегда присутствовала. "Как же нам решить проблему с перегруженной функцией, принимающей как указатель, так и целое число, для случая передачи в нее NULL?"
    И многие люди решали эту проблему вводя самопальный тип cNull и константу Null (или как-то еще). Эти тип и константа всегда и полностью повторяли функционал nullptr с его типом. Проблема была в отсутствии стандарта на эту тему. Представь себе проект с 5-10 библиотек, в каждой из которых свой самопальный nullptr. :)
    Теперь есть стандарт, есть nullptr и std::nullptr_t. Порядок восстановлен. Самое важное - это строгая типизация nullptr - он способен приводиться только к типам указателей.

    Теперь касательно нетипизированного нуля. Давай условимся на одном правиле: почаще и побольше проверять свои догадки. :)
    Я пользуюсь сразу двумя сервисами для этого: cpp.sh и gcc.godbolt.org.
    Первый позволяет быстро покрутить код в работе, а второй позволяет заглянуть в нутро кода после его обработки разными компиляторами.
    Вот, посмотри на эти примеры:
    cpp.sh/9es6c
    https://godbolt.org/g/wUS6Ju

    Думаю, с этими примерами тебе все станет еще понятнее. Особенно - полезность введения в стандарт nullptr.
  • Число 0, как символ?

    @MarkusD Куратор тега C++
    Ivan Sokolov , в библиотеках для встраиваемых систем NULL может иметь осмысленный адрес, обращение по которому запускает аварийный функционал контроллера. В иных ситуациях NULL может так и остаться нулем, просто все тот же аварийный код запускается уже через прерывание при попытке обращения по нулевому адресу. Но это все касается только макроса NULL и довольно старых библиотек для встраиваемых систем.

    А вот на счет nullptr давай обратимся к стандарту. :)
    eelis.net/c++draft/conv.ptr#1

    Но все это не касается самого вопроса. Стандарт однозначен и понятен, более того - очевиден.
    А самое очевидное - то, что использование nullptr вместо NULL или 0 сразу избавляет от неоднозначности выбора между целочисленным аргументом и указателем.
    Но вот использование нетипизированного нуля может привести только к неоднозначности.
  • Число 0, как символ?

    @MarkusD Куратор тега C++
    romy4 , Ivan Sokolov , Airat1995 , числовой литерал 0 является свободно конвертируемым, он автоматически приводится к любому простому типу, включая указатели и вещественные числа. Константа nullptr тут не при чем и никак явно с нулем не связана.
    Airat1995 использовал 0, а не nullptr, поэтому у него и появилась неоднозначность перегрузки.
  • Освобождается ли память по завершению выполнения функции, если массив инициализировать внутри функции?

    @MarkusD Куратор тега C++
    pixik , так ты одним "спасибо" и не ограничивайся. Помечай ответ как решение, как все хорошие мальчики делают.
  • С++: Вызов различных конструкторов в зависимости от пользовательского ввода?

    @MarkusD Куратор тега C++
    Дмитрий Кустерский , если конструкторы не оптимизируются, значит что код самого класса запрещает эти оптимизации. Это проблема.
    У студии, кстати, слишком много настроек оптимизации, чтобы говорить о результате по изменению только одной из них.
    В общем, однозначную причину отсутствия оптимизации в твоем случае определить без детального разбирательства нельзя.
  • Когда имеет значение порядок подключения заголовочных файлов?

    @MarkusD Куратор тега C++
    vipermagi , "В-третьих" можно исключать, более подробной информации уже не будет.
    Если изложенное непонятно, я могу сделать отсылки к стандарту где это все описано "во-сто-раз-еще-более-понятно"{sarcasm}. :)
  • Перегрузка операций с++?

    @MarkusD Куратор тега C++
    @dero
    Вань, такие лабораторные даны не для того чтоб самому в них разбираться, а для общения с преподавателем. Только он тебе скажет, что именно ему хотелось сказать вот этим текстом. Любой третьей стороне этот текст покажется простым неупорядоченным подмножеством слов из множества всех слов одного из разговорных диалектов русского языка.
  • В чем ошибка std::function?

    @MarkusD Куратор тега C++
    AtomKrieg, в пояснении работы `if( _glClear == NULL)` все не так.
    en.cppreference.com/w/cpp/utility/functional/funct...
    en.cppreference.com/w/cpp/utility/functional/funct...
    explicit operator bool ни в коем случае не выведется для проверки небулевой эквивалентности. Поэтому внутри if() будет выполнен именно `bool operator==( const std::function& f, std::nullptr_t );`. И проверка будет правильной.
    `else` там был лишним.

    Там действительно проблема с приведением типов.
    Для приведенной сигнатуры std::function, код присвоения должен быть таким: `_glClearColor = *(PGLCLEARCOLORPROC)SDL_GL_GetProcAddress( "glClearColor" );`.
    Разыменование обязательно, или std::function надо инстанцировать от указателя на функцию.
    Вот пример: cpp.sh/2k4g
  • Как упаковать текстуры в libGDX?

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

    А вот устройств с поддержкой OpenGL 3.x не 42.3%, а 42.3 + 12.8 = 55.1% :) Остальная часть с поддержкой OpenGL 2.0 - это обычно старье с Adreno 200/205, SGX500+ или 1-4 ядерными Mali 400MP. Лично я под вопрос ставлю их практическую ценность и восприятие в качестве целевой аудитории.

    Движок поддерживает все что поддерживает его окружение и операционка. Движку неважен формат текстуры если он(движок), конеч, не порывается читать ее в обход окружения.
    А "самым безопасным" в этом отношении, на самом деле, может быть только TGA. :) Т.к. этот формат на 100% точно передаст качество текстуры и на 100% точно прочитается даже своими руками. ETC - такой же аппаратно-поддерживаемый формат сжатия текстур и он тоже может не поддерживаться какой-нибудь экзотикой из Китая. Шанс есть всегда.
    В манифесте можно указать и требуемую версию OpenGL, и поддерживаемые текстуры. Таким образом можно сделать и несколько .APK файлов для разных GPU, которые будут полностью безопасными.
  • Если не знаю сколько элементов будет в массиве с++?

    @MarkusD Куратор тега C++
    САОД (Структуры и Алгоритмы Обработки Данных) тебе в помощь.
    После изучения теории советую изучить практическую часть через постижение STL ( en.cppreference.com/w/cpp/container ) и книг Николая Джосаттиса (STL - Standard library) или Скота Мейерса (Effective STL).
  • Как правильно настроить Android EGL контекст после того как он удалился при сворачивании?

    @MarkusD Куратор тега C++
    В целом это выглядит очень странно. Контекст случайно не в андроидах <3.0 теряется? В версиях >3.0 я такое наблюдал только в очень старых очень экзотичных китайфонах, которые мы благополучно отфильтровали в маркете. Поведение проекта на такой экзотике в целом напоминало чертовы пляски - все было крайне непредсказуемо и выбивалось из понимания процесса правильной работы самой ОС.
    Наверное ты уже проверил правильность работы Activity и GlSurfaceView вместе с объектом рендерера и с ними все нормально?
    В любом случае, когда приложение уходит в паузу, поверхность рендеринга у GlSurfaceView уничтожается, а контекст, даже если он не уничтожается, он просто отключается от текущего потока. А после выхода из паузы происходит новая связка контекста с поверхностью рендеринга. Т.е. контекст, по своей сути, должен оказаться тем же самым и его не надо перенастраивать.

    В общем, или это экзотика, или что то не так с окружающим SDL кодом. Вариантов точного решения у меня нету, прости что обнадежил тебя.
  • Как правильно настроить Android EGL контекст после того как он удалился при сворачивании?

    @MarkusD Куратор тега C++
    Я с SDL не работаю, поэтому по его поводу ничего сказать не могу. ПО части андроида и OpenGL могу проконсультировать при наличии некоторых уточнений. Первое - GlSurfaceView используем? Если да, то дергаем ли метод `setPreserveEGLContextOnPause(true)`? Второе - правильные ли `android:configChanges` у нас стоят в манифесте? Это все препятствует ненужной потере контекста при сворачивании. Третье - делаем ли мы `surface_view.getHolder().setFormat()` с нужным форматом, в котором будет рисоваться кадр через контекст (да, в доке функция deprecated, только без нее все так же ничего не работает как положено)? Если форматы круто не совпадают, черный экран неминуем.