Advertisement
PaulPaulAga

Untitled

Mar 7th, 2021
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.63 KB | None | 0 0
  1. #include <thread>
  2. #include <mutex>
  3. #include <iostream>
  4. #include <chrono>
  5. #include <utility>
  6. #include <vector>
  7. #include <queue>
  8. #include <memory>
  9. #include <random>
  10. #include <cassert>
  11.  
  12. using namespace std;
  13. using namespace chrono;
  14.  
  15. using time_value = chrono::microseconds;
  16.  
  17. template<typename T>
  18. class ThreadSaveQueue {
  19. public:
  20.   T front() {
  21.     lock_guard<mutex> l(_m);
  22.     return _data.front();
  23.   }
  24.  
  25.   void push(T value) {
  26.     lock_guard<mutex> l(_m);
  27.     _data.push(move(value));
  28.   }
  29.  
  30.   void pop() {
  31.     lock_guard<mutex> l(_m);
  32.     _data.pop();
  33.   }
  34.  
  35.   bool empty() {
  36.     lock_guard<mutex> l(_m);
  37.     return _data.empty();
  38.   }
  39.  
  40. private:
  41.   queue<T> _data;
  42.   mutex _m;
  43. };
  44.  
  45. template<typename T>
  46. class Task {
  47. public:
  48.   Task(T _value, int _id, bool _last = false) : value(std::move(_value)), id(_id), last(_last) {}
  49.  
  50.   T &get() {
  51.     return value;
  52.   }
  53.  
  54.   bool isLast() {
  55.     return last;
  56.   }
  57.  
  58.   int getId() {
  59.     return id;
  60.   }
  61.  
  62. private:
  63.   T value;
  64.   int id;
  65.   bool last;
  66. };
  67.  
  68. template<typename T>
  69. using TaskQueue = ThreadSaveQueue<shared_ptr<Task<T>>>;
  70.  
  71. template<typename T>
  72. class Generator {
  73. public:
  74.   Generator() = default;
  75.  
  76.   virtual shared_ptr<Task<T>> generate() = 0;
  77.  
  78.   virtual bool empty() = 0;
  79.  
  80.   template<typename Container>
  81.   void run(shared_ptr<Container> toInsert) {
  82.     while (!empty())
  83.       toInsert->push(generate());
  84.   }
  85. };
  86.  
  87. class StringGenerator : public Generator<string> {
  88. public:
  89.   StringGenerator() : _current("a"), _last('a'), _count(4), id(-1) {}
  90.   explicit StringGenerator(size_t count) :
  91.       _current("a"), _last('a'), _count(count) {}
  92.  
  93.   shared_ptr<Task<string>> generate() override {
  94.     if (_count) {
  95.       if (_last <= 'z')
  96.         _current.back() = _last++;
  97.       else {
  98.         _last = 'a';
  99.         _current += _last++;
  100.       }
  101.       _count--;
  102.       id++;
  103.     }
  104.     return make_shared<Task<string>>(_current, id, !_count);
  105.   }
  106.  
  107.   bool empty() override {
  108.     return !((bool) _count);
  109.   }
  110.  
  111. private:
  112.   string _current;
  113.   char _last;
  114.   size_t _count;
  115.   int id;
  116. };
  117.  
  118. class RanStrGenerator : public Generator<string> {
  119. public:
  120.   RanStrGenerator() : _count(4), _size(5), _id(0) {}
  121.  
  122.   RanStrGenerator(size_t count, size_t size) : _count(count), _size(size), _id(0) {}
  123.  
  124.   shared_ptr<Task<string>> generate() override {
  125.     assert(!empty());
  126.     _id++;
  127.     return make_shared<Task<string>>(_randomString(), _id, _id == _count - 1);
  128.   }
  129.  
  130.   bool empty() override {
  131.     return _id >= _count;
  132.   }
  133.  
  134. private:
  135.   string _randomString() {
  136.     static string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  137.     string res;
  138.     res.reserve(_size);
  139.     for (size_t i = 0; i < _size; ++i) {
  140.       res.push_back(letters[random() % letters.size()]);
  141.     }
  142.     return res;
  143.   }
  144.  
  145. private:
  146.   size_t _count;
  147.   size_t _size;
  148.   size_t _id;
  149. };
  150.  
  151. template<typename T>
  152. class Handler {
  153. public:
  154.   explicit Handler(string name = "Base handler") : _name(std::move(name)) {}
  155.  
  156.   virtual void handle(shared_ptr<Task<T>> task) = 0;
  157.  
  158.   virtual string name() {
  159.     return _name;
  160.   }
  161. protected:
  162.   string _name;
  163. };
  164.  
  165. class StringHasher : public Handler<string> {
  166. public:
  167.   explicit StringHasher(uint8_t hash = 11) : Handler("String hasher " + to_string(hash)), _hash(hash) {}
  168.  
  169.   void handle(shared_ptr<Task<string>> task) override {
  170.     for (char &ch : task->get())
  171.       ch ^= _hash;
  172.   }
  173.  
  174. private:
  175.   uint8_t _hash;
  176. };
  177.  
  178. template<typename T>
  179. class Line {
  180. public:
  181.   explicit Line(shared_ptr<Handler<T>> handler) : _handler(std::move(handler)), _stop(false) {}
  182.  
  183.   void setInQueue(shared_ptr<ThreadSaveQueue<shared_ptr<Task<T>>>> q) {
  184.     _toHandle = q;
  185.   }
  186.  
  187.   void setOutQueue(shared_ptr<ThreadSaveQueue<shared_ptr<Task<T>>>> q) {
  188.     _nextQueue = q;
  189.   }
  190.  
  191.   shared_ptr<ThreadSaveQueue<shared_ptr<Task<T>>>> inQueue() {
  192.     return _toHandle;
  193.   }
  194.  
  195.   void push(shared_ptr<Task<T>> value) {
  196.     _toHandle->push(value);
  197.   }
  198.  
  199.   void run(time_point<high_resolution_clock> startTime) {
  200.     idleTime = 0;
  201.     while (!_stop) {
  202.       idleStart = high_resolution_clock::now();
  203.       while (_toHandle->empty()) {
  204.         this_thread::sleep_for(10ns);
  205.       }
  206.       idleTime += duration_cast<time_value>(high_resolution_clock::now() - idleStart).count();
  207.       while (!_toHandle->empty()) {
  208.         shared_ptr<Task<T>> value = _toHandle->front();
  209.         _toHandle->pop();
  210.         _inTimes.push_back(duration_cast<time_value>(high_resolution_clock::now() - startTime).count());
  211.         _handler->handle(value);
  212.  
  213.         if (value->isLast())
  214.           _stop = true;
  215.         _outTimes.push_back(duration_cast<time_value>(high_resolution_clock::now() - startTime).count());
  216.         _nextQueue->push(value);
  217.       }
  218.     }
  219.   }
  220.  
  221.   const vector<size_t> &getInTimes() {
  222.     return _inTimes;
  223.   }
  224.  
  225.   const vector<size_t> &getOutTimes() {
  226.     return _outTimes;
  227.   }
  228.  
  229.   size_t getIdleTime() {
  230.     return idleTime;
  231.   }
  232.  
  233. protected:
  234.   shared_ptr<Handler<T>> _handler;
  235.   shared_ptr<ThreadSaveQueue<shared_ptr<Task<T>>>> _toHandle;
  236.   shared_ptr<ThreadSaveQueue<shared_ptr<Task<T>>>> _nextQueue;
  237.   vector<size_t> _inTimes;
  238.   vector<size_t> _outTimes;
  239.   bool _stop;
  240.   size_t idleTime;
  241.   time_point<high_resolution_clock> idleStart;
  242. };
  243.  
  244. template<typename T>
  245. class Conveyor {
  246. public:
  247.   Conveyor(shared_ptr<Generator<T>> generator, vector<shared_ptr<Line<T>>> conveyor)
  248.       : _generator(std::move(generator)), _conveyor(std::move(conveyor)) {
  249.     _conveyor[0]->setInQueue(make_shared<ThreadSaveQueue<shared_ptr<Task<T>>>>());
  250.     for (size_t i = 1; i < _conveyor.size(); ++i) {
  251.       _conveyor[i]->setInQueue(make_shared<ThreadSaveQueue<shared_ptr<Task<T>>>>());
  252.       _conveyor[i - 1]->setOutQueue(_conveyor[i]->inQueue());
  253.     }
  254.     _handled = make_shared<ThreadSaveQueue<shared_ptr<Task<T>>>>();
  255.     _conveyor.back()->setOutQueue(_handled);
  256.   }
  257.  
  258.   void run() {
  259.     vector<thread> threads;
  260. //    threads.emplace_back(_threadGenerator, _generator, _conveyor.front()->inQueue());
  261.     auto c = high_resolution_clock::now();
  262.     for (const shared_ptr<Line<T>> &line: _conveyor) {
  263.       threads.emplace_back(_threadLine, line, c);
  264.     }
  265.     _generator->run(_conveyor.front()->inQueue());
  266.  
  267.     for (thread &t : threads)
  268.       t.join();
  269.     _conveyorRunTime = duration_cast<time_value>(high_resolution_clock::now() - c).count();
  270.   }
  271.  
  272.   void printStats() {
  273.     cout << "Conveyor run time: " << _conveyorRunTime << "ms" << endl;
  274.     string sep = "\t\t";
  275.     for (size_t i = 0; i < _conveyor[0]->getInTimes().size(); ++i) {
  276.       cout << i << sep;
  277.       for (size_t j = 0; j < _conveyor.size(); ++j) {
  278.         cout << _conveyor[j]->getInTimes()[i] << "-" << _conveyor[j]->getOutTimes()[i] << sep;
  279.       }
  280.       cout << endl;
  281.     }
  282.   }
  283.  
  284. private:
  285.   static void _threadLine(shared_ptr<Line<T>> line, time_point<high_resolution_clock> startTime) {
  286.     line->run(startTime);
  287.   }
  288.  
  289.   static void _threadGenerator(shared_ptr<Generator<T>> generator, shared_ptr<TaskQueue<T>> toInsert) {
  290.     generator->run(toInsert);
  291.   }
  292. private:
  293.   shared_ptr<Generator<T>> _generator;
  294.   vector<shared_ptr<Line<T>>> _conveyor;
  295.   shared_ptr<TaskQueue<T>> _handled;
  296.   size_t _conveyorRunTime;
  297. };
  298.  
  299. void runConveyor() {
  300.   vector<shared_ptr<Line<string>>> lines;
  301.   lines.push_back(make_shared<Line<string>>(make_shared<StringHasher>(StringHasher(0))));
  302.   lines.push_back(make_shared<Line<string>>(make_shared<StringHasher>(StringHasher(1))));
  303.   lines.push_back(make_shared<Line<string>>(make_shared<StringHasher>(StringHasher(2))));
  304.   Conveyor<string> con(make_shared<RanStrGenerator>(10, 5000), lines);
  305.   con.run();
  306.   con.printStats();
  307. }
  308.  
  309. int main() {
  310.   runConveyor();
  311.   return 0;
  312. }
  313.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement