Simplified implementation of ThreadSafeValueCache

This commit is contained in:
Anthony J. Thibault 2016-01-05 11:08:08 -08:00
parent 9ea6079c64
commit a21b604746
2 changed files with 7 additions and 39 deletions

View file

@ -1198,16 +1198,8 @@ void Avatar::updatePalms() {
rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation);
// update thread-safe caches
_leftPalmRotationCache.merge([&](const glm::quat& value, bool hasPending, const glm::quat& pendingValue) {
return leftPalmRotation;
});
_rightPalmRotationCache.merge([&](const glm::quat& value, bool hasPending, const glm::quat& pendingValue) {
return rightPalmRotation;
});
_leftPalmPositionCache.merge([&](const glm::vec3& value, bool hasPending, const glm::vec3& pendingValue) {
return leftPalmPosition;
});
_rightPalmPositionCache.merge([&](const glm::vec3& value, bool hasPending, const glm::vec3& pendingValue) {
return rightPalmPosition;
});
_leftPalmRotationCache.set(leftPalmRotation);
_rightPalmRotationCache.set(rightPalmRotation);
_leftPalmPositionCache.set(leftPalmPosition);
_rightPalmPositionCache.set(rightPalmPosition);
}

View file

@ -17,53 +17,29 @@
// It allows many threads to get or set a value atomically.
// This provides cache semantics, any get will return the last set value.
//
// It also provides a mechanism for the owner of the cached value to reconcile
// the cached value with it's own internal values, via the merge method.
//
// For example: This can be used to copy values between C++ code running on the application thread
// and JavaScript which is running on a different thread.
template <typename T>
class ThreadSafeValueCache {
public:
ThreadSafeValueCache(const T& v) : _value { v }, _pending { v }, _hasPending { false } {}
// The callback function should have the following prototype.
// T func(const T& value, bool hasPending, const T& pendingValue);
// It will be called synchronously on the current thread possibly blocking it for a short time.
// it gives thread-safe access to the internal cache value, as well as the pending cache value
// that was set via the last set call. This gives the cache's owner the opportunity to update
// the cached value by resolving it with it's own internal state. The owner should then return
// the resolved value which will be atomically reflected into the cache.
template <typename F>
void merge(F func) {
std::lock_guard<std::mutex> guard(_mutex);
_value = func((const T&)_value, _hasPending, (const T&)_pending);
_hasPending = false;
}
ThreadSafeValueCache(const T& v) : _value { v } {}
// returns atomic copy of the cached value.
T get() const {
std::lock_guard<std::mutex> guard(_mutex);
if (_hasPending) {
return _pending;
} else {
return _value;
}
return _value;
}
// will reflect copy of value into the cache.
void set(const T& v) {
std::lock_guard<std::mutex> guard(_mutex);
_hasPending = true;
_pending = v;
_value = v;
}
private:
mutable std::mutex _mutex;
T _value;
T _pending;
bool _hasPending;
// no copies
ThreadSafeValueCache(const ThreadSafeValueCache&) = delete;