synchronized_wrapper.h 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  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 <algorithm>
  6. #include <mutex>
  7. namespace Common {
  8. /**
  9. * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
  10. * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
  11. * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type
  12. * (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
  13. */
  14. template <typename T>
  15. class SynchronizedWrapper {
  16. public:
  17. template <typename... Args>
  18. SynchronizedWrapper(Args&&... args) : data(std::forward<Args>(args)...) {}
  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. return *this;
  48. }
  49. T& operator*() {
  50. return wrapper->data;
  51. }
  52. const T& operator*() const {
  53. return wrapper->data;
  54. }
  55. T* operator->() {
  56. return &wrapper->data;
  57. }
  58. const T* operator->() const {
  59. return &wrapper->data;
  60. }
  61. private:
  62. SynchronizedWrapper<T>* wrapper;
  63. };
  64. } // namespace Common