В системе с:
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
std::atomic<uint8_t>::is_always_lock_free // => false
std::atomic<uint16_t>::is_always_lock_free // => true
Насколько я понимаю, тип
std::atomic<uint_least8_t>
будет 8 бит и не будет блокироваться.
Если да, то что мне писать, если я хочу, чтобы атомарный тип состоял не менее чем из 8 бит и всегда был свободен от блокировки? (при условии, что такой тип существует) Есть ли лучшая альтернатива, чем:
std::atomic<
typename std::conditional<
std::atomic<uint8_t>::is_always_lock_free,
uint8_t,
uint16_t
>::type
>
(для простоты я не включил код if std::atomic<uint16_t>
не блокируется)
Также нет абсолютного требования, чтобы atomic<x>
действительно хранил x
. Таким образом, в довольно странном случае, когда 16-битные данные свободны от блокировки, я ожидал бы, что 8-битные типы будут использовать 16-битное хранилище.
IMO решение, которое вы предоставили, достаточно простое. Очевидно, вы хотите где-нибудь указать псевдоним типа, но на этом все готово. Работа с поведением, зависящим от платформы, всегда была сложной задачей
@hvd Чем больше я об этом думаю, тем больше мне нравится ваше предложение. Я думаю, что это хороший компромисс между удобочитаемостью / обслуживанием и оптимизацией. Пуленепробиваемое метапрограммирование для поиска лучшего типа без блокировок оказывается довольно тяжелым и трудным для чтения.
Что ж, шаблон немного запутан, но его использование довольно интуитивно понятно:
#include <atomic>
#include <cstdint>
#include <iostream>
template <typename T, typename... others>
class first_lockfree
{
// forward declare internal template
template <bool, typename...> struct cond;
// use this if is_always_lock_free == true
template <typename condT, typename... condTs>
struct cond<true, condT, condTs...>
{
// use first template argument as it is_always_lock_free
using type = condT;
};
// use this if is_always_lock_free == false
template <typename condT, typename... condTs>
struct cond<false, condT, condTs...>
{
// use main template with first template parameter removed
using type = typename first_lockfree<condTs...>::type;
};
public:
using type =typename cond<std::atomic<T>::is_always_lock_free, T, others...>::type;
};
int main(int, char**)
{
using uint8_lockfree_t = first_lockfree<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>::type;
std::cout << sizeof(uint8_lockfree_t) << std::endl;
std::cout << std::atomic<std::uint8_t>::is_always_lock_free << std::endl;
std::cout << std::atomic<std::uint16_t>::is_always_lock_free << std::endl;
std::cout << std::atomic<std::uint32_t>::is_always_lock_free << std::endl;
std::cout << std::atomic<std::uint64_t>::is_always_lock_free << std::endl;
return 0;
}
На самом деле, я ожидал бы, что
uint_fast8_t
будет typedef для некоторого типа lock-free. Это тоже не гарантируется, но вы можете проверить, достаточно ли это для вас.