Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: std::atomic  (Прочитано 17202 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« : 14-02-2017 09:20 » 

https://msdn.microsoft.com/en-us/library/hh874651.aspx

чисто в занимательных целях заинтересовался, есть ли способ узнать, является ли структура Ty - trivially copyable - хоть на этапе компилирования, хоть в рантайме. Ну чтобы 100% стрельнуло, если подсунул не  trivially copyable
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 14-02-2017 21:19 » 

У структуры Ty нет подобных свойств. Зато есть параметризированная структура std::atomic<Ty>.
http://www.cplusplus.com/reference/atomic/atomic/

Леш, попробуй развернуть вопрос.
« Последнее редактирование: 14-02-2017 21:22 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #2 : 15-02-2017 05:02 » 

Ром, ну, к примеру, я обернул структуру
Код:
struct s1
{
int a;
int b;
};

std::atomic<s1> S1;
- тут всё верно

а вот тут мне захотелось, скажем, имя ещё добавить, строку
Код:
struct s2
{
int a;
int b;
QString name;
};

std::atomic<s2> S2;
и это уже ошибка

Кстати, стреляет таки в данном Qt-шном случае. Есть какая-то волшебная проверка в классе atomic

Код:
      static_assert(__is_trivially_copyable(_Tp),
    "std::atomic requires a trivially copyable type");

https://msdn.microsoft.com/ru-ru/library/mt679189.aspx

однако Улыбаюсь Оказывается, всё уже изобретено
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 15-02-2017 07:26 » 

Методы load/store занимаются копированием структуры. На время копирования действует блокировка. Т.ч. QString вполне безопасен. При store для старого объекта вызовется деструктор. Различие T для std::atomic заключается в разной поддержке простых типов, указателей и сложных типов.

Добавлено через 5 минут и 47 секунд:
http://www.cplusplus.com/reference/type_traits/is_trivially_copyable/
Trait-класс для проверки, является ли объект легко копируемым. Это С++11.
« Последнее редактирование: 15-02-2017 07:32 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #4 : 15-02-2017 07:40 » 

то есть, экземпляр типа T копируется не тупо "побитно", а всё-таки оператором =  ?

Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 15-02-2017 22:35 » 

По порядку...

Цитата
T
    Type of the contained value.
    This shall be a trivially copyable type.

Что же это такое?

Цитата
A trivially copyable type is a type whose storage is contiguous (and thus its copy implies a trivial memory block copy, as if performed with memcpy), either cv-qualified or not. This is true for scalar types, trivially copyable classes and arrays of any such types.

Почти memcpy-like, но средствами C++:

Цитата
A trivially copyable class is a class (defined with class, struct or union) that:

    * uses the implicitly defined copy and move constructors, copy and move assignments, and destructor.
    * has no virtual members.
    * its base class and non-static data members (if any) are themselves also trivially copyable types.

Т.е. только неявные конструкторы и инициализаторы копирования и перемещения, а также неявный деструктор. Т.е. их код полностью под контролем языка. Без вирутальных, чтобы не было в объекте сложного поведения. Никакого наследования. Получается: сишный struct, базовый числовой тип или любой указатель.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #6 : 16-02-2017 05:11 » 

ну так тогда получается, что

Т.ч. QString вполне безопасен.

QString как раз не и подходит, хотя бы потому, что активно юзает copy-on-write

И его, значит, придётся заменить на массив wchar_t

Добавлено через 4 минуты и 4 секунды:
указатель вроде тоже опасно. При копировании появится два указателя на одну память

При этом предупреждатор на указатель никак не среагирует )
« Последнее редактирование: 16-02-2017 05:16 от Алексей++ » Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 16-02-2017 06:56 » 

Да, я не сразу вчитался. Никакого постороннего кода.

Логично, что объект под указателем автоматом менеджица не сможет.
« Последнее редактирование: 16-02-2017 06:58 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #8 : 16-05-2017 06:47 » 

поясните один момент. Скажем, данная функция должна возвращать уникальных идентификатор для любого потока
Код: (C++)
uint64_t GetNewUID()
{
        static std::atomic<uint64_t> uid(0);
        return ++uid;
}

но вызывает сомнения операция инкремента - будет ли она тут атомарной ? Как она там устроена?

Допустим, где-то в глубинах данного кода один поток вызвал uid.store(uid.load()+1), следом второй  uid.store(uid.load()+1), но потом оба потока вернули load() , то есть одинаковое значение (и один идентификатор будет пропущен). А это неправильно

Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 16-05-2017 07:06 » 

хотя, отладчик показывает вызов функции

Код: (C++)
      __int_type
      operator++() noexcept
      { return __atomic_add_fetch(&_M_i, 1, memory_order_seq_cst); }

так что ложная тревога  Краснею
Записан

darkelf
Молодой специалист

ua
Offline Offline

« Ответ #10 : 16-05-2017 07:12 » 

поясните один момент. Скажем, данная функция должна возвращать уникальных идентификатор для любого потока
Код: (C++)
uint64_t GetNewUID()
{
        static std::atomic<uint64_t> uid(0);
        return ++uid;
}

но вызывает сомнения операция инкремента - будет ли она тут атомарной ? Как она там устроена?

Допустим, где-то в глубинах данного кода один поток вызвал uid.store(uid.load()+1), следом второй  uid.store(uid.load()+1), но потом оба потока вернули load() , то есть одинаковое значение (и один идентификатор будет пропущен). А это неправильно

Насколько я понял, сорри, не силён в C++, советуют делать через fetch_add, т.е., наверное, что-то типа такого:
Код: (C++)
uint64_t GetNewUID()
{
        static std::atomic<uint64_t> uid(0);
        return std::fetch_add(&uid, 1) + 1;
}
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #11 : 16-05-2017 07:43 » 

darkelf, тогда уж

return std::fetch_add(&uid, 1);

но у меня тут нет метода fetch_add, да и некрасиво как-то.
Записан

darkelf
Молодой специалист

ua
Offline Offline

« Ответ #12 : 16-05-2017 07:56 » 

Как я понял fetch_add() возвращает предыдущее значение, до изменения. Если-бы у Вас было uid++, то надо было-бы делать так, как Вы сказали. А для ++uid надо или использовать add_fetch() - он есть только в GCC и не стандартизирован, или fetch_add(&uid, 1) + 1, как было предложено ранее. В любом случае - как мы уже увидели - компилятор сам всё сделал правильно.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #13 : 16-05-2017 08:38 » new

darkelf, да, судя по содержимому, вроде там всё нормально устроено.
Записан

Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines