• Почему GCC не видит встроенную атомарную операцию?

    AshBlade
    @AshBlade Автор вопроса
    Просто хочу быть счастливым
    Разобрался.
    Есть 2 замечания:
    1. Поближе посмотрел на сигнатуру

    bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder)


    Короче говоря, мне нужно было передавать не указатели, а указатели на указатели. Исправил:

    if (__atomic_compare_exchange(&l.head->next,  (struct entry**)NULL, &new_next, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))


    Но потом начал ловить SEGFAULT. И тут пришел к 2 замечанию

    2. Не заметил следующего в документации:

    This built-in function implements an atomic compare and exchange operation. This compares the contents of *ptr with the contents of *expected. If equal, the operation is a read-modify-write operation that writes desired into *ptr. If they are not equal, the operation is a read and the current contents of *ptr are written into *expected. weak is true for weak compare_exchange, which may fail spuriously, and false for the strong variation, which never fails spuriously. Many targets only offer the strong variation and ignore the parameter. When in doubt, use the strong variation.


    Т.е. если значение во 2 аргументе не равно значению из 1, то (!!!) по месту указателя 2 записывается полученное из указателя 1 значение. А у меня там был NULL (конец списка обозначается NULL). Заменил на корректно выделенный элемент списка и все заработало

    int main(int argc, char const *argv[])
    {
        struct list l;
    
        l.head = (struct entry *)malloc(sizeof(struct entry));
        l.head->next = NULL;
        l.head->value = 123;
        struct entry *old_next = (struct entry *)malloc(sizeof(struct entry));
        old_next->next = NULL;
        old_next->value = 555;
        l.head->next = old_next;
    
        struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
        new_next->value = 444;
        new_next->next = NULL;
        if (__atomic_compare_exchange(&l.head->next, &old_next, &new_next, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
        {
            printf("ok\n");
            printf("success: next = %d\n", l.head->next->value);
        }
        else
        {
            printf("failed\n");
        }
    
        return 0;
    }


    Не хочу возиться со всякими dummy узлами, поэтому буду использовать __sync_bool_compare_and_swap. Вот такой код сработает:
    int main(int argc, char const *argv[])
    {
        struct list l;
    
        l.head = (struct entry *)malloc(sizeof(struct entry));
        l.head->next = NULL;
        l.head->value = 123;
    
        struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
        new_next->value = 444;
        new_next->next = NULL;
    
        if (__sync_bool_compare_and_swap(&l.head->next, (struct entry *)NULL, new_next))
        {
            printf("ok\n");
            printf("success: next = %d\n", l.head->next->value);
        }
        else
        {
            printf("failed\n");
        }
    
        return 0;
    }


    UPD: спасибо res2001, разобрался лучше. итоговый вариант

    #include <stdatomic.h>
    
    int main(int argc, char const *argv[])
    {
        struct list l;
    
        l.head = (struct entry *)malloc(sizeof(struct entry));
        l.head->next = NULL;
        l.head->value = 123;
    
        struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
        new_next->value = 444;
        new_next->next = NULL;
        struct entry *tmp = NULL;
        if (atomic_compare_exchange_strong(&l.head->next, &tmp, new_next))
        {
            printf("ok\n");
            printf("success: next = %d\n", l.head->next->value);
        }
        else
        {
            printf("failed\n");
        }
    
        return 0;
    }


    Просто надо создать переменную указатель, которой присвоить NULL. Также использовал atomic_compare_exchange_strong из stdatomic вместо расширения GCC - он под капотом использует __atomic_* вместо устаревшего __sync_*
    Ответ написан
    1 комментарий
  • Как в C++ создать массив с неизвестным числом элементов?

    @dima20155
    you don't choose c++. It chooses you
    Вектор лишь класс, который предоставляет удобный способ работать с базовой структурой данных типа массив, только динамический (количество элементов можно изменить в момент исполнения программы)
    Невозможно создать массив переменного числа элементов на этапе компиляции

    Так что есть два выхода:
    1. Создать массив со статически определенным количеством элементов (например, 100), но заведомо большим, чем введет пользователь (но опять же, это важно проверять)
    2. Создать динамический массив, хранящий данные в куче (используя std::vector или просто new/malloc)

    https://stackoverflow.com/questions/68073934/how-t...
    Ответ написан
    1 комментарий
  • Почему в наутилусе папка распаковывается за 1 секунду, а в Windows 1 минуту?

    vabka
    @vabka
    Токсичный шарпист
    Потому что в винде zip очень древний и неоптимизированный.
    Лучше использовать winrar или 7zip для распаковки - тогда тоже будет быстро.
    Ответ написан
  • Как подключить библиотеку TgBot к срр проекту?

    Vapaamies
    @Vapaamies
    Разработчик будущей ОС для ПК размером 250 МБ
    Это означает, что программа собралась, но при запуске не может найти нужную DLL, поскольку она не видна через PATH и не лежит рядом с программой. Доступность системе можно проверить командой where:
    where TgBot.dll
    Ответ написан
    4 комментария
  • Как устранить ошибку конверсии при использовании битовых полей?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как устранить ошибку конверсии при использовании битовых полей?

    Не использовать битовые поля. Серьёзно. Удобств на копейку а мороки на рубль.
    Ответ написан
    4 комментария
  • Существует ли максимально простой и универсальный способ сборки проектов с GitHub в готовый exe?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Репозиторий проекта - это не что-то стандартное. Авторы вольны применять любые процессы и скрипты для сборки. Может когда-то какой-нибудь ЧатЖПТ и сможет "прочитать" ридми ЛЮБОГО проекта и проделать всё необходимое для его сборки, но пока что такой инструмент мало реалистичен. Если разработчик сам не настроил CI/CD в проекте, то никак без него это сейчас не сделать.
    Ответ написан
    Комментировать
  • Что такое кластерный индекс в mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Кластерный индекс... это на самом деле понятие крайне виртуальное.

    Что такое обычный некластерный индекс? берём выражение индекса, считаем его значение для каждой записи, сортируем и пишем на диск. Получаем отдельную структуру, в которой выражение индекса сортировано. Когда потребуется искать заданное значение этого выражения, мы вместо просмотра от записи к записи сразу половинным делением быстренько найдём нужное значение, возьмём из него уникальный идентификатор записи, и обратимся за записью. Если в таблице 1000 записей, то для поиска заданного значения без индекса нам в среднем пришлось бы просмотреть 500 записей, а с индексом - всего 10.

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

    В MySQL (точнее, в используемом по умолчанию движке InnoDB) первичный индекс, во-первых, существует ВСЕГДА, во-вторых, определяется так (в статье, на которую дали ссылку, имеются неточности в пункте 2):
    1. Если первичный ключ задан явно, то его выражение является также и выражением кластерного индекса. Или иначе - первичный ключ и есть кластерный индекс.
    2. Если первичный ключ явно не задан, но в таблице имеется индекс, отвечающий всем следующим требованиям:
      • является уникальным
      • не является функциональным, в т.ч. не использует в выражении вычисляемые поля
      • не использует в выражении поля, которые определены как допускающие значение NULL

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


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

    Фактически - именно так.

    Создаётся ли отдельная таблица или просто упорядочивается хранение существующих данных?

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

    Если данные упорядочиваются этим индексом, допустим по ID, то почему при select без сортировки данные могут возвращаться в произвольном порядке, а не отсортированные по ID по-умолчанию?

    Если не задан явно ORDER BY, сервер имеет право вернуть записи в любом порядке, как ему удобнее. В большинстве случаев, но не всегда, он будет возвращать записи в порядке чтения с диска...

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

    ===

    PS. Кстати, правило выбора индекса, который будет использоваться в качестве кластерного, имеет неприятный побочный эффект. Если у некоторых полей, входящих в какие-то индексы, изменяется свойство NULLability, то это может привести к изменению того, какой из имеющихся индексов станет использоваться в качестве первичного по пункту 2. В результате мы получим невозможность использования INSTANT / INPLACE методов, и будет использован длинный COPY. Впрочем, ситуация такая крайне редка.
    Ответ написан
    2 комментария
  • Что считать корректным вводом целого числа?

    GavriKos
    @GavriKos
    А почему это вы у нас спрашиваете, а не у того кто поставил задание?
    Ответ написан
    Комментировать
  • Как лучше всего обновлять большое количество windows server?

    hint000
    @hint000
    у админа три руки
    Ответ написан
    Комментировать
  • Почему make file компилятора выдает ошибку, что функция переопределяется?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Похоже на какие-нибудь циклические инклуды.
    У вас в data_process.h случайно не включается data_process.c?
    Так делать не надо.
    Ответ написан
    6 комментариев
  • Компилятор выдаёт ошибку при попытке вызвать sizeof() относительно моего массива. Как исправить ошибку?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    В C параметр функции не может быть массивом, только указателем. Синтаксис "имя с квадратными скобками" несёт тот же смысл, что и "имя со звёздочкой" когда речь идёт о параметрах функции. Если внутри функции взять sizeof от такого параметра результат будет равен sizeof от указателя. Это очень распространённая ошибка и компилятор говорит тебе об этом. Если тебе нужен размер массива переданного в функцию -- передавай его отдельно, например отдельным параметром.

    sizeof(dict)/sizeof(const char)

    Здесь ещё одна ошибка: dict -- это массив указателей (на самом деле указатель на такой массив, но по крайней мере, ты ожидал массив указателей), но ты делишь размер массива на размер const char а не на размер const char *. Во избежание таких ошибок для вычисления размера массива обычно пишут sizeof(dict)/sizeof(dict[0]).
    Ответ написан
    Комментировать
  • Как настроить или создать интернет прокси или шлюз на домашнем пк что бы с его ip заходить удаленно?

    SignFinder
    @SignFinder
    Wintel\Unix Engineer\DevOps
    Нужен выданный провайдером публичный ip адрес, желательно статический и маршрутизатор с VPN сервером на борту.
    Либо выданный провайдером публичный ip адрес, желательно статический и развернуть любой VPN сервер на компьютере, если нет маршрутизатора.
    Ответ написан
    5 комментариев
  • Какая структура с лимитом памяти позволит ускорить поиск по огромному файлу с набором бинарных данных?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Если записи фиксированного размера и отсортированы, а поиск идёт по префиксу, то никаких дополнительных структур не надо, достаточно двоичного поиска.
    Ответ написан
  • Можно ли настроить несколько пулов адресов для клиентов на сервере OpenVPN?

    SignFinder
    @SignFinder
    Wintel\Unix Engineer\DevOps
    Два серверных файла конфигурации с разными портами и настройками пулов адресов и два соответствующих им клиентских файла конфигурации
    Ответ написан
    1 комментарий
  • Контринтуитивный синтаксис объявления нескольких переменных одного типа?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    можно подумать, что при объявлении указателя, символ * относится к имени(не как часть, а как что-то зависящее от него), а не к типу.

    Если взять стандарт языка (например C99) и почитать главы Declarations, Type Specifiers и Declarators, то можно увидеть, что он разделяет declaration-specifiers, в который входят только слова и declarators, в который входят скобочки и звёздочки. Т.е. твой вывод по сути верный.

    Там же можно увидеть, что часть называемую declarator всегда можно обернуть в скобки, из чего можно извлечь следующий вывод: часть объявления вокруг которой можно поставить скобки самым широким образом относится к конкретному идентификатору, оставшаяся часть -- ко всему списку. Т.е. const char *a, b; можно превратить в const char (*a), b, но нельзя превратить в const (char *a), b или в char (const *a), b.

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

    saboteur_kiev
    @saboteur_kiev Куратор тега IT-образование
    software engineer
    Есть ощущение, что ваши цельные проекты слишком простые и маленькие и вы обманываете сами себя, говоря что вам нравится решать полный цикл задач.
    В любом направлении слишком много есть инструментов и технологий, чтобы изучить все, и фуллстак разработчик не может знать и делать все - обычно он работает в определенной области с привычными инструментами, а не прям везде и все.

    Например "обслуживание и поддержка" уже имеющегося софта - чем не разработка?
    Или вы не видите разницы между условным MS office 1.0 и MS Office XP и современной версией?

    Все зависит от проекта.
    Ответ написан
    Комментировать
  • Как программным методом удалить одну из итераций цикла for?

    Adamos
    @Adamos
    Решается проблема XY.
    Тут в принципе не имеет смысла for, а нужен while(vector.size() < 5)
    Шаманство с индексом цикла - плохая практика, она аукнется в новых стандартах, например.
    Ответ написан
    Комментировать
  • Округление при подсчёте в С++?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Потому что 0.1 в двоичном коде не представимо конечным числом.
    0.110 = 0.0(0011)2
    Записывая это число в 32-битовый float вы получаете 1.100110011001100110011012 * 2-4 или 0.10000000149011611938476562510
    Соответственно, когда вы 20 раз прибавляете 0.1 к -1, вы не получаете 1. Вы получаете 1.00000029802322387695312510.
    Это число, очевидно, больше единицы, поэтому условие цикла не срабатывает и 21я строка не выводится.
    Ответ написан
    6 комментариев
  • Почему в https не используется асимметричное шифрование?

    @Everything_is_bad
    Поискав в интернете
    обычно там же рядом пишут причину, "дорогая" это операций на больших объемах данных, так что в процессе контакта, создают сессионный симметричный ключ (который в этом процессе сложно как-то перехватить) и дальше уже им с меньшими затратами можно шифровать
    https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D0%B0%D...
    Ответ написан
    Комментировать