2022-09-15
include <iostream>
include <string>
include <queue>
include <thread>
include <chrono>
include <limits.h>
include <condition_variable>
using namespace std;
using namespace chrono;
struct Courier {
int64_t arriveTime;
bool operator < (const Courier &co) const {
return arriveTime < co.arriveTime;
}
bool operator > (const Courier &co) const {
return arriveTime > co.arriveTime;
}
};
struct Order{
string id;
string name;
int prepareTime; // second
int64_t dispatchTime;
int64_t finishTime; // finish finishTime
Order() {
prepareTime = 0;
finishTime = 0;
id = "";
name = "";
}
Order(Order *order) {
this->id = order->id;
this->name = order->name;
this->prepareTime = order->prepareTime;
this->finishTime = order->finishTime;
}
bool operator < (const Order &od) const
{
return finishTime < od.finishTime;
}
bool operator > (const Order &od) const
{
return finishTime > od.finishTime;
}
};
template<typename NODE>
class MyQueue {
public:
virtual int Init(int cap) = 0;
virtual void Deinit() = 0;
virtual int Push(NODE order) = 0;
virtual NODE GetFrontAndPop(void) = 0;
virtual bool IsFull(void) = 0;
virtual bool IsEmpty(void) = 0;
};
template<typename NODE>
class Queue : public MyQueue<NODE> {
public:
Queue() {
this->capicity = INT_MAX;
}
int Init(int cap)
{
this->capicity = cap;
pthread_mutex_init(&(this->mutex), NULL);
}
void Deinit()
{
// lock , free order
pthread_mutex_lock(&(this->mutex));
while (!this->que.empty()) {
this->que.pop();
}
pthread_mutex_unlock(&(this->mutex));
//
pthread_mutex_destroy(&(this->mutex));
return;
}
int Push(NODE order)
{
//cout<<"input order id: "<<order.id<<endl;
if (this->que.size() >= this->capicity) {
return -1;
}
this->que.push(order);
return 0;
}
bool IsFull() {
return this->que.size() == this->capicity;
}
bool IsEmpty() {
return this->que.empty();
}
NODE GetFrontAndPop() {
while (this->que.empty()) {
// error
std::this_thread::sleep_for(1000ms);
cout<<"que is empty\n";
}
NODE order = this->que.front();
this->que.pop();
return order;
}
private:
int capicity;
queue<NODE> que;
pthread_mutex_t mutex;
};
template<typename NODE>
class ProQueue : public MyQueue<NODE> {
public:
ProQueue() {
this->capicity = INT_MAX;
}
int Init(int cap)
{
this->capicity = cap;
pthread_mutex_init(&(this->mutex), NULL);
}
void Deinit()
{
// lock , free order
pthread_mutex_lock(&(this->mutex));
while (!this->que.empty()) {
this->que.pop();
}
pthread_mutex_unlock(&(this->mutex));
//
pthread_mutex_destroy(&(this->mutex));
return;
}
int Push(NODE order)
{
if (this->que.size() >= this->capicity) {
return -1;
}
this->que.push(order);
return 0;
}
bool IsFull() {
return this->que.size() == this->capicity;
}
bool IsEmpty() {
return this->que.empty();
}
NODE GetFrontAndPop() {
while (this->que.empty()) {
// error
std::this_thread::sleep_for(1000ms);
cout<<"que is empty\n";
}
NODE order = this->que.top();
this->que.pop();
return order;
}
private:
int capicity;
priority_queue<NODE, vector<NODE>, greater<NODE>> que;
pthread_mutex_t mutex;
};
class Input {
public:
int Product(MyQueue<Order> *myque, void *args)
{
Order order = (Order)args;
Order od(order);
int ret = myque->Push(order);
return ret;
}
};
//typedef (int*)Rand(int min, int max);
class Dispatch {
public:
virtual int DispatchOrder(MyQueue<Order> *que, MyQueue<Courier> *couriers) = 0;
int RegistRand();
int CariesArrivedTime(int min, int max)
{
// rand from min to max, [min, max]
return 0;
}
void AddFoodWait(int prepareTime)
{
this->foodwait += prepareTime;
}
int64_t GetFoodWait()
{
return foodwait;
}
void AddCariesWait(int wait)
{
this->carieswait += wait;
}
int64_t GetCariesWait()
{
return carieswait;
}
void AddOrders() {
orders++;
}
int64_t GetOrders() {
return orders;
}
int64_t GetAvgFoodWaitTime() {
if (orders == 0) {
return 0;
}
return foodwait / orders;
}
int64_t GetAvgCariesWaitTime() {
if (orders == 0) {
return 0;
}
return carieswait / orders;
}
private:
int64_t foodwait;
int64_t carieswait;
int64_t orders;
};
class Matched : public Dispatch
{
public:
int DispatchOrder(MyQueue<Order> *que, MyQueue<Courier> *couriers)
{
Queue<Order> *q = (Queue<Order> *)que;
Queue<Courier> *cou = (Queue<Courier> *)couriers;
if (cou->IsEmpty()) {
cout<<"couries is empty!\n";
return -3;
}
Order order = q->GetFrontAndPop();
Courier courier = cou->GetFrontAndPop();
if (order.finishTime >= courier.arriveTime) {
AddCariesWait(order.finishTime - courier.arriveTime);
} else {
AddFoodWait(courier.arriveTime - order.finishTime);
}
AddOrders();
cout<<"Match Dispatch "<<order.name<<" "<<order.finishTime<<" couries arrived time: "<<courier.arriveTime<<endl;
}
};
class FIFO : public Dispatch
{
public:
int DispatchOrder(MyQueue<Order> *que, MyQueue<Courier> *couriers)
{
ProQueue<Order> q = (ProQueue<Order>)que;
Order order = q->GetFrontAndPop();
auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
if (now < order.finishTime) {
q->Push(order);
return -2;
}
cout<<"Match Dispatch "<<order.name<<" "<<order.prepareTime<<" "<<order.finishTime<<" "<<now<<endl;
return 0;
}
};
class Notify {
public:
int FilePath(const char *path) {
}
void Print(string s) {
cout<<s<<endl;
}
void Event(string s) {
}
void Log(string) {
}
};
enum STRATEGIE {
STRATEGIE_MATCH = 0x01, // match strategie
STRATEGIE_FIFO // fifo strategie
};
struct Config {
STRATEGIE st;
int32_t cap;
};
class Server{
private:
std::condition_variable full;
std::condition_variable emp;
std::mutex mtx; // 保护队列
int64_t capicity;
int64_t nums; // 队列中的数量
int64_t emptys; // 空闲数量
int stragegie; // 策略
Dispatch *dispatch;
MyQueue<Order> *que;
MyQueue<Courier> *couriers;
Notify notify;
public:
int InitServer(Config *conf);
void DeInitServer();
int ReadData(const char* file);
int DispatchOrder();
int Statistics();
};
int Server::InitServer(Config *conf)
{
// default conf
if (conf == NULL) {
stragegie = STRATEGIE_MATCH;
capicity = 10;
} else {
stragegie = conf->st;
capicity = conf->cap;
}
if (stragegie == STRATEGIE_MATCH) {
Matched *match = new Matched();
dispatch = (Dispatch*)match;
Queue<Order> *que = new Queue<Order>();
que->Init(capicity);
this->que = (Queue<Order>*)que;
this->couriers = new Queue<Courier>();
} else if (stragegie == STRATEGIE_FIFO) {
FIFO *fifo = new FIFO();
dispatch = (Dispatch*)fifo;
ProQueue<Order> *que = new ProQueue<Order>();
que->Init(capicity);
this->que = (ProQueue<Order>*)que;
this->couriers = new ProQueue<Courier>();
}
return 0;
}
int Server::ReadData(const char* file)
{
auto start = system_clock::now();
auto end = system_clock::now();
// fen duan duqu?
static int times = 0;
while (true) {
std::this_thread::sleep_for(2000ms);
std::unique_lock<std::mutex> lock(mtx);
this->emp.wait(lock, [this]{return !que->IsFull();});
static int64_t id = 0;
for (int i = 0; i < 2; i++) {
Order order;
order.name = "rndNO" + to_string(id) + "*";
order.id = to_string(id);
id++;
order.prepareTime = rand() % 15000; // 0-15s
order.dispatchTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
order.finishTime = order.dispatchTime + order.prepareTime;
que->Push(order);
Courier courier;
courier.arriveTime = order.dispatchTime + rand() % 15000;
if(couriers->Push(courier) != 0) {
cout<<"couriers push error\n";
}
notify.Print("push " + order.name + " " + to_string(order.finishTime));
}
times++;
if (times >= 10) {
int64_t fw = dispatch->GetAvgFoodWaitTime();
int64_t cw = dispatch->GetAvgCariesWaitTime();
notify.Print("food wait time: " + to_string(fw) + "ms couries wait time: " + to_string(cw));
return 0;
}
emp.notify_all();
}
}
int Server::DispatchOrder()
{
while (true) {
std::this_thread::sleep_for(100ms);
std::unique_lock<std::mutex> lock(mtx);
this->emp.wait(lock, [this]{return !que->IsEmpty();});
if (dispatch->DispatchOrder(que, couriers) == -2) { // order not prepared, couries not arrived
}
emp.notify_all();
}
}
int ProductOrder(Server* server, const char* file)
{
return server->ReadData(file);
}
int DispatchOrder(Server* server)
{
return server->DispatchOrder();
}
int main()
{
/* Queue myque;
myque.Init(10);
Input input;
//myque.Init(100);
Matched match;
thread read(Read, "/home/err", &myque);
thread disp(DispatchMeth, &myque, &match);
read.join();
disp.join(); */
Server server;
server.InitServer(NULL);
thread read(ProductOrder, &server, "/home/err");
thread disp(DispatchOrder, &server);
//thread disp1(DispatchOrder, &server);
read.join();
disp.join();
//disp1.join();
cout<<"hello world\n";
}