Dyikot, Тем хуже.
Предположение с выходом за границу буфера в силе.
Вероятен еще вариант не порчи соседних переменных, а чтения чужих или мусорных данных за границей буфера и использования их в расчете. Это могло бы объяснить разные результаты по одним входным данным, т.к. "мусор" - может быть все время разный.
Например стековая переменная вы выходите за границу переменной и читаете какую-то область на стеке - т.к. стек выделен весь, то SIGFAULT не будет - можно и читать и писать. Только что в итоге получится - не предсказуемо. Ну вот и у вас как-то так получается. Такая же ситуация может быть и с динамической памятью и со статической.
По непонятным причинам результаты могут быть другими.
Если имеются ввиду разные результаты по одним и тем же входным данным, то да, есть проблема.
Если же входные данные разные, то вполне вероятно ожидать и разных результатов. По моему так? Не дурно было бы просчитать результаты другим способом, чтоб знать результат наверняка и уже сравнивать с ним, как с эталоном.
То что программа в Debug и Release сборке ведет себя по разному - свидетельствует об ошибках. Скорее всего где-то выход за границу буфера с порчей соседних переменных. Довольно часто встречающаяся ошибка.
Часто компиляторы в Debug сборках добавляют паддинги вокруг переменных для собственных целей, они могут предотвращать порчу соседних переменных.
Погоняйте под valgrindом или другим анализатором. Но это может и не дать результата, тогда только анализ кода поможет.
Dyikot, Что да? При чем тут постоянная задержка?
Я просто описываю механизм с помощью которого мне удавалось делать в потоке достаточно точные не большие паузы.
У меня там не было фиксированной задержки. Задача была добиться пробуждение потока каждую 1мс с желательно равными промежутками времени, при этом еще учитывалось время работы самого потока (он же не моментально отрабатывает) и таймаут следующего пробуждения рассчитывался каждую итерацию с учетом затраченного на работу потока времени. Поэтому реальный таймаут, передаваемый в кондвар был меньше 1 мс.
Dyikot, Никаких особых чудодейственных средств в библиотеках нет, SDL_DelayNS использует что-то, предоставляемое системой.
На линуксе, мне доводилось укладываться по задержкам в 1 мс (+-несколько сот мкс), на высокоприоритетном потоке с RT планированием. Поток должен был просыпаться каждую 1 мс и делать свое черное дело. Ждал на кондваре, т.к. там по мимо пробуждения по таймауту могли быть и другие асинхронные события, которые будили поток.
На десктопных операционках квант времени, выдаваемый потоку (процессу) на работу до его вытеснения 1-10 мс. После истечения кванта поток вытесняется с выполнения ядром ОС. В линуксе, вроде бы, квант времени может быть плавающий, начинает с 10 мс и, если нужно, может уменьшаться вплоть до 1 мс.
Ваши 8 мс вполне укладываются в это ограничение. Если в данный момент времени в системе есть другие потоки, готовые работать, то такие задержки это нормально и я бы вообще не ожидал лучшего результата с применением таймеров (или sleepа того же) и загруженной системе.
Как-то поправить положение, можно, например выделив для этой задачи отдельный высокоприоритетный поток. В линуксе этому потоку так же можно задать Realt-Time планирование с повышенным приоритетом - в этом случае все типичные потоки с "общим" планированием будут менее приоритетны. В винде не знаю, есть ли подобные фишки, но приоритет то поднять точно можно. Еще как вариант привязать поток к одному ядру процессора - теоретически это может улучшить работу с кешем процессора. Обычно, так делают, при интенсивном обмене сетевым трафиком. В линуксе можно указать affinity для конкретного сетевого адаптера и если процесс в user space, который работает с этим адаптером, будет так же работать на этом же ядре, то будет неплохой буст в производительности. Поможет ли это вам, сказать трудно, надо проверять.
В целом идея Mercury13 с засечкой времени и проверкой в нужных местах мне нравится. Сам так иногда делаю в подходящих ситуациях. Но в этом случае ваш поток должен что-то делать во время активного ожидания. Если ему заняться не чем, то можно повисеть на condvarе с таймером. Читал, что в кондваре несколько другой механизм используется, чем в таймерах и тех же sleepах, правда это относилось к линуксу. И кондвар может быть более отзывчивым из-за этого. Так же видел проекты с применением этой идеи, где были реализованы собственные таймера с ожиданием на кондваре.
Но это я все про вариант без корутин, с обычной асинхронщиной. Как это все ложиться на корутины сказать не могу.
Миллисекундные задержки - это все таки мягкое реальное время, в жестком в микросекундах считают задержки и там уже совсем другие ОС. Что касается стандартных десктопных ОС (линукс и винда), то они ни разу не Real-Time и ожидать от них RT поведения не стоит. В Линуксе еще можно использовать ядро с RT_PREEMPT патчем, который делает линукс немного более Real-Time, но это уже не обычное ядро, этим надо специально заморачиваться.
RT ОСь отличается от не RT тем, что в RT четко определенные задержки для всех операций. В винде и линуксе, если ядро, например, начнет что-то подкачивать из файла подкачки, то задержки легко могут увеличиться в несколько раз. Файл подкачки в этом случае - это просто как пример того чем может быть занята ОСь, когда не дает работать вашей задаче.
rudaki29rus, Теоретически, можно в поддержке уточнить, по каким критериям они блочат ресурсы в интернете. Кто составляет белые списки, где их можно увидеть.
rudaki29rus, С помощью сервисов whois можно проверить кому принадлежат адреса: ваш домашний внешний адрес и рабочий внешний адрес. И если вдруг окажется, что это одна и та же лавочка - ну значит, скорее всего, блокировать не будут. И вообще вдруг адреса окажутся из одной подсети.
Но тут гарантий нет, как на то что блокировать не будут (просто шансы увеличиваются на это), так и на то, что whois прояснит ситуацию.
В остальном, никто, кроме самого оператора, вам на этот вопрос не ответит.
А оператор на этот вопрос вам отвечать не станет, даже если очень просить.
Думаете, с просто так юрики платят серьезные деньги за подключение? У юриков обычно именно заявленная скорость, без "до".
Не знаю, как там выходят из положения в крупных компаниях, но провайдер просто физически не способен гарантировать постоянную скорость ко всему интернету, т.к. он не контролирует в интернете всё.
Юрики обычно пытаются гарантировать постоянную скорость до, например, своего филиала в городе N. В этом случае организуют "выделенную" линию и за нее платят отдельно и это не интернет.
Возможен вариант, когда надо обеспечить гарантированную скорость к определенным узлам/сайтам в интернет, тогда это должно быть обоюдно (сайт/узел должен то же захотеть предоставлять свои услуги с гарантированной скоростью этому юрику), в этом случае наверное ставят на площадке провайдера свой сервер, чтоб он оказался внутри сети оператора с гарантированной скоростью.
Была на моей практике история, когда моя мухосранская контора подключалась к клирингу одного крупного банка в Москве - банчок сразу сказал - не хотите проблем со скоростью передачи подключайтесь через такого и такого оператора (у них было 3 или 4 оператора на выбор). Нам тогда повезло, что и моя контора сидела на одном из операторов из списка, так что особо ничего не пришлось менять. И т.д. и т.п.
В любом случае речь никогда не идет о гарантированной скорости на весь интернет.
Пока гугл и стим не ушли официально из РФ, то они наверняка имели свои сервера в Ростелеке и других крупных операторах. Поэтому до их ресурсов скорость была приличной. И даже в этом случае, если, например, вы пытались смотреть видосик на ютубе, которого нет в кэше локального сервера, то он мог сначала тормозить, пока видосик не загрузится в кэш, потом скорость выравнивалась.
Белые списки, видимо, тупо по диапазонам IP сетей и/или доменным именам.
Вам повезло, что ваш рабочий адрес попал в белый диапазон домашнего оператора.
По каким причинам он в белых списках - это к оператору. Может быть и на работе и дома один и тот же оператор - не будет же он сам себя блочить. Или другие причины.
Если не повезет - удалят из списка и работать перестанет.
Пользуйтесь пока дают :-)
Дмитрий Шумов, Есть 2 варианта того, как ВПН клиент попадает внутрь сети за ВПН сервером:
1. через NAT на ВПН сервере
2. с помощью настроенной маршрутизации
Какой вариант у вас?
Обычно, когда настраивают ВПН по мануалам из интернета, то делают через NAT. В этом случае маршруты на компах внутри сети (за ВПН сервером) настраивать не надо. Но CIFS через NAT может работать криво (или вообще не работать).
Так что думаю, вам нужен вариант с маршрутизацией. Но для этого требуется добавить маршрут до ВПН сети на каждый комп внутри сети (за ВПН сервером), к которому вы хотите получить доступ с ВПН клиента. Единственный вариант, когда этого можно не делать - это если ВПН сервер является одновременно и сервером по умолчанию для компов внутри сети (в вашем варианте, похоже это не так).
Компилятор сам приведет -2 в нужный формат и присвоит полученную комбинацию битов беззнаковой переменной. Как правило удобней это делать с -1, в дополнительном коде будет 0xFFFFFFFF.
Возможно это то же UB, но такой подход регулярно встречается в коде.
KIberKOtlEtf, Есть смысл делать сборку для винды на винде :-) Поставьте виртуалку с виндой и собирайте там: msys2+mingw или MSVS/MS build вам в помощь.
Это избавит вас от малопонятных на данном этапе ошибок, связанных с разными платформами и компиляторами.
Писать кросс-платформенное ПО на С/С++ - это отдельный скил у программиста.
На других языках, в большинстве случаев, не существует особой проблемы. Потому что об этом уже подумали создатели языка и его стандартной библиотеки. Но это не значит, что эти языки лучше, скорее наоборот, они принуждают программиста использовать именно предлагаемые инструменты для реализации его целей. Но может быть инструменты эти не так хороши или нужно что-то несколько большее, чем реализовано в библиотеке. Но, справедливости ради, в подовляющем большинстве случаев обычно достаточно возможностей.
Это не значит, что на С/С++ нельзя писать кросс-платформенно. Можно и многие так и делают, только кросс-платформенность должен в этом случае обеспечить сам программист, а не ЯП.
Хотя сам по себе С++ вполне себе кросс-платформенный и его стандартная библиотека то же (правда могут быть нюансы даже на одной платформе, но на разных компиляторах), но стандартная библиотека С++ не включает в себя интерфейс для сетевого взаимодействия. Даже более-менее сложная работа с файловой системой появилась там не так давно.
Если вы используете в кросс-платформенном ПО какую-то библиотеку, то библиотека то же должна быть кросс-платформенной и поддерживать те платформы, для которых вы планируете собирать свое ПО.
На сколько я знаю boost.asio прекрасно работает под виндой, так что в этом плане не вижу проблем.
На счет WinSock - по большому счету на винде других альтернатив нет для работы с сетью, тот же boost.asio внутри должен использовать WinSock в каком-то виде, чтоб выполнять свой функционал на винде. Точно так же, как и любые другие ЯПы, где есть поддержка сети, на винде используют WinSock.
WinSock это то же, что и сокеты беркли на линуксе. Попробуйте написать что-то под линь с сетью без сокетов.
Akina, В винде есть утилита cmdkey для управления Диспетчером учетных записей из ком.строки.
Можно попробовать с ее помощью в скрипте предварительно нужную запись создавать, потом удалять.
Кстати, можно начать с того, что проверить список сохраненных учетных записей после выполнения net use. Возможно они все таки сохраняются, как временные, даже без /persistent.
Еще есть утилита vaultcmd, то же вроде бы позволяет делать аналогичные действия, но я ее не использовал, так что это не точно. Из power shell то же можно управлять учетными записями.
AslHack, Немного добавил вывода в ваш тест
Посмотрите результат на годболте.
Полезно будет сравнить ошибки gcc и clang. Поведение clang по умолчанию более адекватное - он предупреждает про усечение размера результата в операции sizeof где в операнде была адресная арифметика.
Если со статическим массивом используется адресная арифметика, то происходит не явное преобразование имени массива в указатель на его первый элемент. Соответственно теряется информация о полном типе массива. Именно об этом предупреждает clang при компиляции (а gcc молчит как пратизан) и это хорошо видно в выводе sizeof.
То же самое происходит при передаче массива в функцию.
Т.е. zippo + 1 имеет тип int[2], а не int[4][2] как можно было бы предположить.
Увлекательная беседа :) AslHack, zippo - адрес всего массива zippo[4][2], тип int[4][2]; zippo[0] - адрес первой строки массива zippo, тип int[2]; *zippo - то же, что и zippo[0]
Учитывая, что значения адреса для zippo, zippo[0], *zippo, zippo[0][0] - одно и то же, то это может вводить в заблуждение. Поэтому вывод вашего последнего теста надо рассматривать совместно с типами, т.е. смотреть пару адрес и тип совместно - только тогда вы поймете, что думает о них компилятор.
Поскольку тип в строковом представлении получить в run-time проблематично, то можно вместо типа использовать результат sizeof и уже по этому значению определять тип элемента.
Проще всего, чтоб не делать ошибок, при работе со статическими массивами всегда работать с ними через индексацию, без адресной арифметики. И относится к имени массива именно как к массиву, а не как к его первому элементу (т.е. не употребляйте *zippo).
Исходный код утилиты ничего не даст - там обращение к драйверу ядра через netlink по умолчанию (или через ioctl если netlink не доступен). Сама утилита лишь отправляет запросы, получает ответы и выводит их на экран.
Так что это вопрос точно к драйверу конкретного адаптера, а не к ethtool.
Имя массива - это адрес начала массива. Тип статического массива - это массив, а не тип его первого элемента, поэтому и имя рассматривается как адрес начала массива.
С двумерным массивом все работает аналогично. Имя двумерного массива - это адрес начала всего двумерного массива.
Напишите тест где выводите sizeof(arrOne) и sizeof(arrTwo) и разные другие варианты, которые придут в голову. Это даст понимание того, как компилятор воспринимает имя массива.
Предположение с выходом за границу буфера в силе.
Вероятен еще вариант не порчи соседних переменных, а чтения чужих или мусорных данных за границей буфера и использования их в расчете. Это могло бы объяснить разные результаты по одним входным данным, т.к. "мусор" - может быть все время разный.
Например стековая переменная вы выходите за границу переменной и читаете какую-то область на стеке - т.к. стек выделен весь, то SIGFAULT не будет - можно и читать и писать. Только что в итоге получится - не предсказуемо. Ну вот и у вас как-то так получается. Такая же ситуация может быть и с динамической памятью и со статической.