Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Design an abstract alarm system
- #include "stdafx.h"
- #include <queue>
- #include <thread>
- #include <mutex>
- #include <atomic>
- #include <chrono>
- #include <condition_variable>
- #include <functional>
- #include <iostream>
- #include <time.h>
- #include <random>
- #include <memory>
- #include <string>
- #include <future>
- using std::chrono::system_clock;
- typedef std::chrono::system_clock::time_point timestamp_t;
- std::mutex print_mut;
- std::string fmt_timestamp(const timestamp_t & ts)
- {
- const time_t t = std::chrono::system_clock::to_time_t(ts);
- struct tm loctime;
- localtime_s(&loctime, &t);
- char buf[128];
- strftime(buf, 128, "%X", &loctime);
- return std::string(buf);
- }
- struct Alarm
- {
- timestamp_t timestamp;
- int data;
- void execute(Alarm & a)
- {
- std::lock_guard<std::mutex> lk(print_mut);
- std::cout << "\tAlarm " << data << ", @ " << fmt_timestamp(a.timestamp) <<
- ", now: " << fmt_timestamp(std::chrono::system_clock::now()) << '\n';
- }
- };
- bool operator < (const Alarm & a, const Alarm & b)
- {
- // default priority_queue is MAX-HEAP
- // we want earlier Alarms to stay
- // at the head of the heap, i.e. MIN-HEAP
- return a.timestamp > b.timestamp;
- }
- // thoughts
- class AlarmSystem
- {
- bool running;
- std::priority_queue<Alarm> Q;
- std::mutex mut;
- std::condition_variable signal;
- std::thread loop;
- public:
- AlarmSystem() : running(true), loop(&AlarmSystem::run, this){}
- ~AlarmSystem()
- {
- running = false;
- {
- std::lock_guard<std::mutex> lk(mut);
- signal.notify_one();
- }
- loop.join();
- }
- void add(Alarm & a)
- {
- std::lock_guard<std::mutex> lk(mut);
- Q.push(a);
- signal.notify_one();
- }
- size_t size() { return Q.size(); }
- void run()
- {
- while(running)
- {
- std::unique_lock<std::mutex> lk(mut);
- // wait either 1 second or while Queue empty or until running
- if(Q.empty()) { signal.wait(lk); }
- // sometimes signal wakes up accidently
- // need to check the queue again
- if(Q.empty()) { continue; }
- const timestamp_t at = Q.top().timestamp;
- const timestamp_t curtime = std::chrono::system_clock::now();
- if(curtime < at)
- {
- const std::chrono::system_clock::duration dur = at - curtime;
- // wait with time out
- signal.wait_for(lk, dur);
- continue;
- }
- Alarm a = Q.top(); // copy the earliest alarm from the top of the queue
- Q.pop(); // remove it from the queue
- // asynchronously launch alarm handler
- std::async(std::launch::async, [a](Alarm a) { a.execute(a); }, a);
- }
- }
- };
- struct Timer
- {
- bool running;
- std::thread timer_thread;
- Timer() : running(true), timer_thread(&Timer::run_timer, this) {}
- void run_timer()
- {
- while(running)
- {
- std::this_thread::sleep_for(std::chrono::duration<int>(1));
- std::string now(fmt_timestamp(std::chrono::system_clock::now()));
- std::lock_guard<std::mutex> lk(print_mut);
- std::cout << "Timer:" << now << '\n';
- }
- }
- ~Timer() { running = false; timer_thread.join(); }
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- unsigned seed = 1;
- std::random_device rd;
- std::mt19937 RANDOM(rd());
- const int MAX_FUTURE = 10;
- const int MAX_ALARMS = 1000;
- std::uniform_int_distribution<> uniform(1, MAX_FUTURE);
- typedef std::chrono::duration<int> seconds_t;
- AlarmSystem alarm_system;
- Timer timer;
- timestamp_t now = std::chrono::system_clock::now();
- timestamp_t last_alarm = now;
- int id = 0;
- for(int j = 0; j < MAX_ALARMS; ++j, ++id)
- {
- int d = uniform(RANDOM);
- Alarm a;
- a.data = id;
- now = std::chrono::system_clock::now();
- a.timestamp = now + seconds_t(d);
- last_alarm = std::max(a.timestamp, last_alarm);
- {
- std::lock_guard<std::mutex> lk(print_mut);
- std::cout << "size: "<< alarm_system.size() << '\t' << a.data << " scheduled at: " << fmt_timestamp(a.timestamp) << '\n';
- }
- alarm_system.add(a);
- std::this_thread::sleep_for(std::chrono::milliseconds(uniform(RANDOM)));
- }
- std::this_thread::sleep_until(last_alarm);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment