keker123

Untitled

Apr 20th, 2023
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.91 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <cstdint>
  4. #include <mutex>
  5. #include <shared_mutex>
  6. #include <set>
  7. #include <atomic>
  8. #include <vector>
  9. #include <iostream>
  10. #include "memory"
  11.  
  12. /*
  13.  * Потокобезопасный связанный список.
  14.  */
  15.  
  16.  
  17. template<typename T>
  18. struct TNode {
  19.     T value;
  20.     TNode<T> *next;
  21.     TNode<T> *prev;
  22.     mutable std::shared_mutex valuemutex_; // for value and isreflock
  23.     mutable std::shared_mutex nodemutex_; // for prev and next and isDeleted
  24.     std::atomic<bool> isTail;
  25.     std::atomic<bool> isDeleted;
  26.     TNode(T v, TNode<T> *n, TNode<T> *p) : value(std::move(v)), next(std::move(n)), prev(std::move(p)) {}
  27.     TNode(TNode<T> *n, TNode<T> *p) : next(std::move(n)), prev(std::move(p)), isTail(true) {}
  28.  
  29. };
  30.  
  31. template<typename T>
  32. class ThreadSafeList {
  33.     mutable std::shared_mutex headListMutex;
  34.  
  35.     TNode<T> *head = nullptr;
  36.     TNode<T> *tail = nullptr;
  37. public:
  38.     /*
  39.      * Класс-итератор, позволяющий обращаться к элементам списка без необходимости использовать мьютекс.
  40.      * При этом должен гарантироваться эксклюзивный доступ потока, в котором был создан итератор, к данным, на которые
  41.      * он указывает.
  42.      * Итератор, созданный в одном потоке, нельзя использовать в другом.
  43.      */
  44.     ThreadSafeList(){
  45.         TNode<T>* tail_ = new TNode<T>(nullptr, nullptr);
  46.         std::unique_lock<std::shared_mutex> headlock(headListMutex);
  47.         head = tail_;
  48.         tail = tail_;
  49.     }
  50.     class Iterator {
  51.         friend class ThreadSafeList;
  52.         TNode<T>* curr_;
  53.         bool isLocked = false;
  54.     public:
  55.         using pointer = T*;
  56.         using value_type = T;
  57.         using reference = T&;
  58.         using difference_type = std::ptrdiff_t;
  59.         using iterator_category = std::bidirectional_iterator_tag;
  60.  
  61.         Iterator(TNode<T>* node): curr_(std::move(node)){};
  62.  
  63.         ~Iterator(){
  64.             if (curr_ != nullptr) {
  65.                 if (isLocked) {
  66.                     isLocked = false;
  67.                     curr_->valuemutex_.unlock();
  68.                 }
  69.                 if (curr_->isDeleted) { // похер на локи, потому что никто уже ничего не делает с удаленной нодой
  70.                     delete curr_;
  71.                 }
  72.             }
  73.         }
  74.  
  75.         T& operator *() {
  76.             curr_->valuemutex_.lock();
  77.             isLocked = true;
  78.             return curr_->value;
  79.         }
  80.  
  81.         T operator *() const {
  82.             std::shared_lock<std::shared_mutex> lock(curr_->valuemutex_);
  83.             return curr_->value;
  84.         }
  85.  
  86.         T* operator ->() {
  87.             std::shared_lock<std::shared_mutex> lock(curr_->valuemutex_);
  88.             return &(curr_->value);
  89.         }
  90.  
  91.         const T* operator ->() const {
  92.             std::shared_lock<std::shared_mutex> lock(curr_->valuemutex_);
  93.             return &(curr_->value);
  94.         }
  95.  
  96.         Iterator& operator ++() {
  97.             std::unique_lock<std::shared_mutex> lock(curr_->nodemutex_);
  98.             if (isLocked) {
  99.                 isLocked = false;
  100.                 curr_->valuemutex_.unlock();
  101.             }
  102.             auto old = curr_;
  103.             curr_ = curr_->next;
  104.             lock.unlock();
  105.  
  106.             if (old->isDeleted) { // похер на локи, потому что никто уже ничего не делает с удаленной нодой
  107.                 delete old;
  108.             }
  109.             return *this;
  110.         }
  111.  
  112.         Iterator& operator --() {
  113.             std::unique_lock<std::shared_mutex> lock(curr_->nodemutex_);
  114.             if (isLocked) {
  115.                 isLocked = false;
  116.                 curr_->valuemutex_.unlock();
  117.             }
  118.             auto old = curr_;
  119.             curr_ = curr_->prev;
  120.             lock.unlock();
  121.             if (old->isDeleted) {
  122.                 delete old;
  123.             }
  124.             return *this;
  125.         }
  126.  
  127.         bool operator !=(const Iterator& rhs) const {
  128.             return this->curr_ != rhs.curr_;
  129.         }
  130.         bool operator== (const Iterator& rhs) const {
  131.             return !operator!=(rhs);
  132.         }
  133.     };
  134.  
  135.     /*
  136.      * Получить итератор, указывающий на первый элемент списка
  137.      */
  138.     Iterator begin() const {
  139.         std::shared_lock<std::shared_mutex> lock(headListMutex);
  140.         return Iterator(head);
  141.     }
  142.  
  143.     /*
  144.      * Получить итератор, указывающий на "элемент после последнего" элемента в списке
  145.      */
  146.     Iterator end() const {
  147.         return Iterator(tail);
  148.     }
  149.     Iterator cend() const {
  150.         return Iterator(tail);
  151.     }
  152.     /*
  153.      * Вставить новый элемент в список перед элементом, на который указывает итератор `position`
  154.      */
  155.     void insert(Iterator position, const T& value) {
  156.         std::shared_lock<std::shared_mutex> shHeadLock(headListMutex);
  157.         if (head->isTail && tail->isTail) {
  158.             auto newNode = new TNode<T>(T(value), tail, nullptr);
  159.             shHeadLock.unlock();
  160.             std::unique_lock<std::shared_mutex> taillock(tail->nodemutex_);
  161.             tail->prev = newNode;
  162.             std::unique_lock<std::shared_mutex> headlock(headListMutex);
  163.             head = newNode;
  164.         } else if (position == end()){
  165.             shHeadLock.unlock();
  166.             std::unique_lock<std::shared_mutex> taillock(tail->nodemutex_);
  167.             std::unique_lock<std::shared_mutex> tailprevlock(tail->prev->nodemutex_);
  168.             auto newNode = new TNode<T>(T(value), tail, tail->prev);
  169.             tail->prev->next = newNode;
  170.             tail->prev = newNode;
  171.         } else {
  172.             // TODO: insert в середину
  173.         }
  174.     }
  175.  
  176.     /*
  177.      * Стереть из списка элемент, на который указывает итератор `position`
  178.      */
  179.     void erase(Iterator& position) {
  180.         std::unique_lock<std::shared_mutex> lockPosNode(position.curr_->nodemutex_);
  181.         if (position.curr_->prev != nullptr) position.curr_->prev->nodemutex_.lock();
  182.         else headListMutex.lock();
  183.         position.curr_->next->nodemutex_.lock();
  184.         if (position.curr_->prev != nullptr) {
  185.             position.curr_->prev->next = position.curr_->next;
  186.             position.curr_->prev->nodemutex_.unlock();
  187.         } else {
  188.             head = position.curr_->next;
  189.             headListMutex.unlock();
  190.         }
  191.         position.curr_->next->nodemutex_.unlock();
  192.         position.curr_->next->prev = position.curr_->prev;
  193.         position.curr_->isDeleted = true;
  194.         lockPosNode.unlock();
  195.     }
  196. };
  197.  
Add Comment
Please, Sign In to add comment