У меня есть некоторые данные, которые читаются и обновляются несколькими потоками. Оба чтения и записи должны быть атомарными. Я думал сделать это следующим образом:Lockless reader/writer
// Values must be read and updated atomically
struct SValues
{
double a;
double b;
double c;
double d;
};
class Test
{
public:
Test()
{
m_pValues = &m_values;
}
SValues* LockAndGet()
{
// Spin forver until we got ownership of the pointer
while (true)
{
SValues* pValues = (SValues*)::InterlockedExchange((long*)m_pValues, 0xffffffff);
if (pValues != (SValues*)0xffffffff)
{
return pValues;
}
}
}
void Unlock(SValues* pValues)
{
// Return the pointer so other threads can lock it
::InterlockedExchange((long*)m_pValues, (long)pValues);
}
private:
SValues* m_pValues;
SValues m_values;
};
void TestFunc()
{
Test test;
SValues* pValues = test.LockAndGet();
// Update or read values
test.Unlock(pValues);
}
Данных защищен путем кражи указателя на него для каждого чтение и запись, которые должны сделать его потокобезопасен, но это требует два ВЗАИМОСВЯЗАННЫХ инструкции для каждого доступа. Там будет много и чтения и записи, и я не могу сказать заранее, если будет больше чтений или больше записей.
Можете ли вы сделать это более эффективно? Это также блокируется при чтении, но поскольку вполне возможно иметь больше записей, то читает, что нет смысла оптимизировать чтение, если только оно не наносит штраф на запись.
Я думал о том, что читает, приобретая указатель без взаимной инструкции (вместе с порядковым номером), копируя данные, а затем имея способ сказать, изменился ли порядковый номер, и в этом случае он должен повторить попытку. Однако для этого потребуются некоторые барьеры памяти, и я не знаю, может ли это улучшить скорость.
----- EDIT -----
Спасибо всем, большие комментарии! Я действительно не запускаю этот код, но сегодня я попытаюсь сравнить текущий метод с критическим сектором (если я получу время). Я все еще ищу оптимальное решение, поэтому я вернусь к более передовым комментариям позже. Еще раз спасибо!
Что такое проблема с использованием примитивов синхронизации потоков по умолчанию? – naivnomore
Должен признаться, я просто предположил, что могу сделать это быстрее, чем это. 1) Здесь я показываю только один экземпляр, но на самом деле у меня будет, возможно, 10000 экземпляров этих защищенных записей данных, и это будет означать 10000 критических разделов. Но, возможно, это не проблема, я не знаю, я никогда не пробовал что-то подобное. 2) Я надеялся, что могу придумать что-то быстрее, чем критический раздел. Там может быть легко миллионы чтений/записей в секунду. И на личном уровне я просто подумал, что было бы здорово сделать так же быстро, как и по-человечески (возможно?). – Rabbit
Windows CRITICAL_SECTION очень легкий, если только он не должен блокироваться. Я не думаю, что оживленные пользовательские потоки, подобные этому, - это ужасно хорошая идея - вы неявно сигнализируете планировщику, что у вас есть много дел, тогда как на самом деле все наоборот. –