WinAPI _Interlocked * встроенные функции для char, short - PullRequest
2 голосов
/ 22 февраля 2011

Мне нужно использовать функцию _Interlocked *** для char или short, но в качестве входных данных требуется длинный указатель.Кажется, что есть функция _InterlockedExchange8, я не вижу никакой документации по этому вопросу.Похоже, это недокументированная функция.Также компилятор не смог найти функцию _InterlockedAdd8.Буду признателен за любую информацию об этих функциях, рекомендации по использованию / неиспользованию и другие решения.

обновление 1

Я постараюсь упростить вопрос,Как я могу сделать эту работу?

struct X
{
    char data;
};

X atomic_exchange(X another)
{
    return _InterlockedExchange( ??? );
}

Я вижу два возможных решения

  1. Используйте _InterlockedExchange8
  2. Cast another для длинных, делайте обмен иприведите результат обратно к X

Первое - явно плохое решение.Второй выглядит лучше, но как это реализовать?

обновление 2

Что вы думаете о чем-то подобном?

template <typename T, typename U>
class padded_variable
{
public:
    padded_variable(T v): var(v) {}
    padded_variable(U v): var(*static_cast<T*>(static_cast<void*>(&v))) {}
    U& cast()
    {
        return *static_cast<U*>(static_cast<void*>(&var));
    }
    T& get()
    {
        return var;
    }
private:
    T var;
    char padding[sizeof(U) - sizeof(T)];
};

struct X
{
    char data;
};

template <typename T, int S = sizeof(T)> class var;
template <typename T> class var<T, 1>
{
public:
    var(): data(T()) {}
    T atomic_exchange(T another)
    {
        padded_variable<T, long> xch(another);
        padded_variable<T, long> res(_InterlockedExchange(&data.cast(), xch.cast()));
        return res.get();
    }
private:
    padded_variable<T, long> data;
};

Спасибо.

Ответы [ 4 ]

2 голосов
/ 04 апреля 2011

Довольно просто создавать 8-битные и 16-битные блокированные функции, но причина, по которой они не включены в WinAPI, связана с переносимостью IA64. Если вы хотите поддерживать Win64, ассемблер не может быть встроенным, поскольку MSVC больше не поддерживает его. Что касается внешних функциональных блоков, использующих MASM64, они не будут такими же быстрыми, как встроенный код или встроенные функции, поэтому вам разумнее исследовать продвигающие алгоритмы для использования 32-разрядных и 64-разрядных атомарных операций.

Пример реализации взаимосвязанного API: intrin.asm

1 голос
/ 22 февраля 2011

Ну, вы должны обойтись с доступными функциями. _InterlockedIncrement и `_InterlockedCompareExchange доступны в 16- и 32-разрядных вариантах (последний также в 64-разрядном варианте), и, возможно, некоторые другие встроенные встроенные функции также доступны в 16-разрядных версиях, но InterlockedAdd не позволяет кажется, и, похоже, нет никаких блокированных встроенных функций / функций размером в байт.

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

Почему вы работаете с отдельными байтами в любом случае? Придерживайтесь объектов int размера, если у вас нет действительно веской причины использовать что-то меньшее.

1 голос
/ 22 февраля 2011

Создание нового ответа, потому что ваши изменения немного изменили:

  • Использовать _InterlockedExchange8
  • Примените еще одну к длинной, обменяйте и приведите результат обратно к X

Первый просто не сработает. Даже если функция существует, она позволит вам атомарно обновлять байт за раз. Это означает, что объект в целом будет обновлен в серии шагов, которые не будут атомарными.

Второй также не работает, если X не имеет тип POD long. (и если он не выровнен по границе sizeof(long), и если он не того же размера, что и long)

Чтобы решить эту проблему, вам нужно сузить типы X. Во-первых, конечно, гарантированно будет тип POD? Если нет, то у вас совершенно другая проблема, поскольку вы не можете безопасно обрабатывать не POD-типы как необработанные байты памяти.

Во-вторых, какие размеры могут иметь X? Блокированные функции могут обрабатывать 16, 32 и, в зависимости от обстоятельств, могут быть шириной 64 или даже 128 бит.

Охватывает ли это все случаи, с которыми вы можете столкнуться?

Если нет, возможно, вам придется отказаться от этих атомарных операций и согласиться на простые старые блокировки. Заблокируйте Mutex, чтобы гарантировать, что только один поток касается этих объектов одновременно.

1 голос
/ 22 февраля 2011

Почему вы хотите использовать меньшие типы данных?Таким образом, вы можете разместить их в небольшом пространстве памяти?Это просто приведет к ложному совместному использованию и конфликту строк кэша.

Независимо от того, используете ли вы алгоритмы блокировки или без блокировки, идеально, чтобы ваши данные были в блоках не менее 128 байт (или независимо от того, какой размер строки кэша у вас есть).CPU), которые используются только одним потоком одновременно.

...