Альтернатива атоми c<variant> в C ++ - PullRequest
0 голосов
/ 18 февраля 2020

Мой код C ++ 17 использует std::atomic<MyVariant>, который определяется как

using MyVariant = std::variant<std::monostate, bool, unsigned int, int, double, void*>

При использовании современного clang, is_trivially_copyable<MyVariant> верно, но с некоторыми другими компиляторами, такими как современный Intel C (19.0.3), копировать нетривиально. Это означает, что я не могу использовать его в типе atomi c. Я предполагаю, что это связано с его реализацией внутри компилятора Intel - я не думаю, что стандарт требует, чтобы варианты были легко копируемыми.

Теперь я рассматриваю альтернативы. Вот что мне нужно сделать (что я сейчас и делаю с вышеуказанным подходом):

  1. загрузить новый тип atomi c variable / generi c из MyVariant без зная содержащийся тип (например, я не хочу извлекать указанный c тип с помощью std::get)
  2. выполнить сравнение_exchange_weak для нового альтернативного типа, не зная содержащегося в нем типа
  3. сохранить полученное значение обратно в переменную MyVariant правильного типа

Я готов быть немного небезопасным для этого фрагмента кода, который будет небольшим и внутренним.

Я попытался реализовать этот следующий подход, но он не компилируется без std::get содержащегося в нем типа:

MyVariant       val = 42.2;
std::atomic<uint64_t> atomic_v;
atomic_v.store(val);  // fails to compile without a std::get<double>(val)

Пожалуйста, дайте мне знать ваши мысли о том, как я могу оба: 1) делать atomi c операции над 64-битным фрагментом данных без заботы о типе и 2) последующее преобразование его обратно в MyVariant без знания типа. Есть ли способ проанализировать тип варианта и сохранить его / как-нибудь его использовать?

Если это невозможно, мне придется изменить свой API.

1 Ответ

0 голосов
/ 18 февраля 2020

Используя полезные материалы от Игоря Тандетника и KamilCuk, вот решение, которое работает для моих нужд. Это грязно, так как мне нужно поддерживать определение параллельного объединения, а также вариант, который я раскрываю через мой API, но я готов это сделать, и это, похоже, работает и позволяет мне использовать операции atomi c.

Обратная связь приветствуется.

// run the code with something like: clang++ -std=c++17 main.cpp -o main && ./main


#include <atomic>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <variant>

using MyVariant = std::variant<bool, unsigned int, int, double, void*>;

int main(int argc, char const* argv[]) {

    union MyVariantAtomicUnion {
        std::atomic<bool>         bool_v;
        std::atomic<unsigned int> unsigned_v;
        std::atomic<int>          int_v;
        std::atomic<double>       double_v;
        std::atomic<void*>        void_ptr_v;
        bool                      invalid;
    };

    MyVariantAtomicUnion atomic_test_union;

    struct MyVisitor {
        MyVariantAtomicUnion& atomic_test_union_internal;

        MyVisitor(MyVariantAtomicUnion& u) : atomic_test_union_internal{u} {}

        void operator()(int int_var_val) {
            atomic_test_union_internal.int_v.store(int_var_val);
            printf("int value used\n");
        }
        void operator()(double d_var_val) {
            atomic_test_union_internal.double_v.store(d_var_val);
            printf("double value used\n");
        }
        void operator()(bool bool_v) {
            atomic_test_union_internal.bool_v.store(bool_v);
            printf("bool value used\n");
        }
        void operator()(unsigned int val) {
            atomic_test_union_internal.unsigned_v.store(val);
            printf("unsigned  value used\n");
        }
        void operator()(void* val) {
            atomic_test_union_internal.void_ptr_v.store(val);
            printf("void* value used\n");
        }
    };

    MyVariant d_val = 42.22222;

    MyVisitor my_vis{atomic_test_union};
    std::visit(my_vis, d_val);
    printf("After visitation, value is %lf\n",
           atomic_test_union.double_v.load());

    d_val = 55;
    std::visit(my_vis, d_val);
    printf("After visitation, value is %d\n", atomic_test_union.int_v.load());

    d_val = true;
    std::visit(my_vis, d_val);
    printf("After visitation, bool value is %d\n",
           atomic_test_union.bool_v.load());

    d_val = reinterpret_cast<void*>(0xfeedbeef);
    std::visit(my_vis, d_val);
    printf("After visitation, value is %p\n",
           atomic_test_union.void_ptr_v.load());

    return EXIT_SUCCESS;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...