fork download
  1. #include <iostream>
  2. #include <mutex>
  3. #include <thread>
  4. #include <vector>
  5. #include <assert.h>
  6. using namespace std;
  7.  
  8. template <class PtrType, class LockType>
  9. class ELockWrapper
  10. {
  11. public:
  12. class Proxy {
  13. public:
  14. Proxy(PtrType* p, LockType* lock) : ptr(p), mLock(lock) { mLock->Lock(); }
  15. ~Proxy() { mLock->Unlock(); }
  16. PtrType* operator->() { return ptr; }
  17. PtrType operator*() { return *ptr; }
  18. private:
  19. PtrType* ptr;
  20. LockType* mLock;
  21. };
  22.  
  23. ELockWrapper() : ptr(nullptr), lock(nullptr) {}
  24. ELockWrapper(nullptr_t t) : ELockWrapper() {}
  25. ELockWrapper(PtrType *p, LockType* l) : ptr(p), lock(l) {}
  26. ELockWrapper(PtrType *p, LockType& l) : ptr(p), lock(&l) {}
  27. ELockWrapper(const ELockWrapper& copy) = default;
  28.  
  29. ELockWrapper& operator=(const ELockWrapper& x) = default;
  30. bool operator==(const ELockWrapper& cmp) { return cmp.ptr == ptr; }
  31. bool operator!=(const ELockWrapper& cmp) { return !operator==(cmp); }
  32. bool operator==(PtrType* t) { return ptr == t; }
  33. bool operator!=(PtrType* t) { return ptr != t; }
  34. bool operator==(bool b) { return (ptr && b) || (!ptr && !b); }
  35. bool operator!=(bool b) { return !operator==(b); }
  36. operator bool() const { return ptr; }
  37.  
  38. Proxy operator->() {
  39. return Proxy(ptr, lock);
  40. }
  41.  
  42. PtrType operator*() {
  43. return *Proxy(ptr, lock);
  44. }
  45.  
  46. void Delete() {
  47. Proxy(ptr, lock);
  48. delete ptr;
  49. }
  50.  
  51. private:
  52. PtrType* ptr;
  53. LockType* lock;
  54. };
  55.  
  56. /* Anything below this is for testing purposes */
  57.  
  58. struct TestClass {
  59. TestClass(int i) : x(i) {}
  60. void IncX(int numIters) { for(int i = 0; i < numIters; ++i) ++x; }
  61. int x;
  62. };
  63.  
  64. struct TestLock {
  65. TestLock(std::mutex& i) : m(i) {}
  66. void Lock() { m.lock(); }
  67. void Unlock() { m.unlock(); }
  68.  
  69. std::mutex& m;
  70. };
  71.  
  72. void IncThr(ELockWrapper<TestClass, TestLock>tsp, int numIters) {
  73. tsp->IncX(numIters);
  74. }
  75.  
  76. int main() {
  77. TestClass obj(25);
  78. std::mutex m;
  79. TestLock lock(m);
  80.  
  81. ELockWrapper<TestClass, TestLock> thread_safe_ptr(&obj, &lock);
  82. ELockWrapper<TestClass, TestLock> other_thread_safe_ptr = nullptr;
  83. auto thread_safe_ptr_copy = thread_safe_ptr;
  84. obj.x = 26;
  85.  
  86. if(thread_safe_ptr_copy->x != thread_safe_ptr->x) { cout << "Broken - copy" << endl; }
  87. if(thread_safe_ptr->x != obj.x) { cout << "Broken - access" << endl; }
  88. if((*thread_safe_ptr).x != obj.x) { cout << "Broken - dereference" << endl; }
  89. if(thread_safe_ptr != &obj) { cout << "Broken - comparison with ptr" << endl; }
  90. if(other_thread_safe_ptr == thread_safe_ptr) { cout << "Broken - comparison with other wrapper" << endl; }
  91.  
  92. thread_safe_ptr = nullptr;
  93. if(!thread_safe_ptr || thread_safe_ptr == nullptr || thread_safe_ptr == false) { }
  94. else {
  95. cout << "Broken - nullptr comparisons" << endl;
  96. }
  97.  
  98. thread_safe_ptr_copy->x = 0;
  99. std::vector<std::thread> threads;
  100. for(int i = 0; i < 8; ++i) threads.push_back(std::thread(&IncThr, thread_safe_ptr_copy, 1000000));
  101. for(int i = 0; i < 8; ++i) threads[i].join();
  102.  
  103. if(thread_safe_ptr_copy->x != 8000000) { cout << "Broken - concurrency - " << thread_safe_ptr_copy->x << endl; }
  104.  
  105. TestClass* deallocObj = new TestClass(100);
  106. ELockWrapper<TestClass, TestLock> delete_ptr(deallocObj, &lock);
  107. delete_ptr.Delete();
  108. return 0;
  109. }
Success #stdin #stdout 0s 19856KB
stdin
Standard input is empty
stdout
Standard output is empty