I was learning about C++ memory sequence, and I found this code in Unreal Engine5. My question is why not call compare_exchange_strong()
directly instead of load()
first?
FHttpRequest* GetFreeRequest()
{
for (uint8 i = 0; i < Pool.Num(); ++i)
{
if (!Pool[i].Usage.load(std::memory_order_relaxed)) //<-why load first?
{
uint8 Expected = 0u;
if (Pool[i].Usage.compare_exchange_strong(Expected, 1u))
{
Pool[i].Request->Reset();
return Pool[i].Request;
}
}
}
return nullptr;
}
I think it's okay to remove the load()
call and change it to something like this:
FHttpRequest* GetFreeRequest()
{
for (uint8 i = 0; i < Pool.Num(); ++i)
{
uint8 Expected = 0u;
if (Pool[i].Usage.compare_exchange_strong(Expected, 1u))
{
Pool[i].Request->Reset();
return Pool[i].Request;
}
}
return nullptr;
}
why load first?
Because .load(std::memory_order_relaxed)
(read) is fast and .compare_exchange_strong(Expected, 1u)
(read-modify-write) is slow.
This is slow once, and then fast until Usage
is reset.
if (!Pool[i].Usage.load(std::memory_order_relaxed)) {
// ...
if (Pool[i].Usage.compare_exchange_strong(Expected, 1u))
This is slow always
if (Pool[i].Usage.compare_exchange_strong(Expected, 1u))