synchronized_wrapper.h 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <mutex>
  6. namespace Common {
  7. /**
  8. * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
  9. * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
  10. * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
  11. */
  12. template <typename T>
  13. class SynchronizedWrapper {
  14. public:
  15. template <typename... Args>
  16. SynchronizedWrapper(Args&&... args) :
  17. data(std::forward<Args>(args)...) {
  18. }
  19. private:
  20. template <typename U>
  21. friend class SynchronizedRef;
  22. std::mutex mutex;
  23. T data;
  24. };
  25. /**
  26. * Synchronized reference, that keeps a SynchronizedWrapper's mutex locked during its lifetime. This
  27. * greatly reduces the chance that someone will access the wrapped resource without locking the
  28. * mutex.
  29. */
  30. template <typename T>
  31. class SynchronizedRef {
  32. public:
  33. SynchronizedRef(SynchronizedWrapper<T>& wrapper) : wrapper(&wrapper) {
  34. wrapper.mutex.lock();
  35. }
  36. SynchronizedRef(SynchronizedRef&) = delete;
  37. SynchronizedRef(SynchronizedRef&& o) : wrapper(o.wrapper) {
  38. o.wrapper = nullptr;
  39. }
  40. ~SynchronizedRef() {
  41. if (wrapper)
  42. wrapper->mutex.unlock();
  43. }
  44. SynchronizedRef& operator=(SynchronizedRef&) = delete;
  45. SynchronizedRef& operator=(SynchronizedRef&& o) {
  46. std::swap(wrapper, o.wrapper);
  47. }
  48. T& operator*() { return wrapper->data; }
  49. const T& operator*() const { return wrapper->data; }
  50. T* operator->() { return &wrapper->data; }
  51. const T* operator->() const { return &wrapper->data; }
  52. private:
  53. SynchronizedWrapper<T>* wrapper;
  54. };
  55. } // namespace Common