美文网首页
2022-09-20

2022-09-20

作者: Tomasmule | 来源:发表于2022-09-20 17:55 被阅读0次

    readme

    # dispatch
    a project
    
    use  a simple timer(priority queue) to simulate the event
    one thread is to read file , another thread is timer, when the event be touch , then notify.
    
    architecture:
    
    file information :
    data.h: a template data struct , include  hash map(use for matched strategy)  and priority queue(use for FIFO strategy )
    dispatch.h: implement of two strategy. notify event and statistics average food wait time and courier wait time
    error.h: error code 
    type.h: base type 
    server.h: manager source and implement read file.
    
    
    
    demo:
    

    int ProductOrder(Server* server, const char* file)
    {
    pthread_setname_np(pthread_self(), "product");
    return server->ReadData(file);
    }

    int TryDispatchOrder(Server* server)
    {
    pthread_setname_np(pthread_self(), "dispatch");
    return server->TryDispatchOrder();
    }

    int main()
    {
    Config conf;
    conf.st = STRATEGIE_MATCH; // STRATEGIE_MATCH
    string file = "data2.json";
    conf.cap = DEFAULT_MAX_QUEUE_SIZE;

    Server server;
    server.InitServer(&conf);
    
    thread read(ProductOrder, &server, file.c_str());
    thread disp(TryDispatchOrder, &server);
    read.join();
    disp.join();
    server.DeInitServer();
    

    }

    
    compile information:
    compiler: gcc
    cmake: above VERSION 3.16
    
    build Server:
    cmake .
    make clean && make
    ./Server
    
    build Test: must build Server before build Test
    cd test
    cmake .
    make clean && make
    ./Test 
    
    

    data.h

    /*
     * @Author: mayihui
     * @Date: 2022-09-19 20:37:23
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-20 00:21:04
     * @Description: data struct for store the order and courier information
     * if stragegie is Matched, then use the hash map to store orders and couriers
     * if stragegie is FIFO, then user the priority_queue to store orders and couriers.
     */
    
    #ifndef DATA_H
    #define DATA_H
    
    #include <iostream>
    using namespace std;
    
    #define DEFAULT_MAX_QUEUE_SIZE 1000000
    
    template <typename NODE> class MyQueue {
    public:
        virtual ~MyQueue() {}
        virtual bool IsEmpty(void) = 0;
        virtual int Size(void) = 0;
        virtual int Insert(string id, NODE data) = 0;
        virtual void RegisteFree(FREE f) = 0;
        virtual void MyFree(NODE order) = 0; // free the NODE
    };
    
    template <typename NODE> class HashQueue : public MyQueue<NODE> {
    public:
        HashQueue()
        {
            this->capacity = DEFAULT_MAX_QUEUE_SIZE;
            myFree = nullptr;
        }
        HashQueue(int capacity)
        {
            this->capacity = capacity;
            myFree = nullptr;
        }
        virtual ~HashQueue()
        {
            auto it = que.begin();
            while (it != que.end()) {
                auto de = it;
                it++;
                MyFree(de->second);
                RemoveById(de->first);
            }
        }
    
        int Insert(string id, NODE order)
        {
            if (this->que.size() >= this->capacity) {
                return QUEUE_SIZE_IS_FULL;
            }
            if (que.count(id)) {
                return QUEUE_ELEMENT_IS_EXIST;
            }
            que[id] = order;
            return 0;
        }
        void RemoveById(string id)
        {
            if (que.count(id)) {
                this->que.erase(id);
            }
        }
        bool IsEmpty()
        {
            return this->que.empty();
        }
        bool IsExist(string id)
        {
            return que.count(id);
        }
        NODE GetValbyId(string id)
        {
            return que[id];
        }
        int Size()
        {
            return que.size();
        }
        void MyFree(NODE order)
        {
            if (myFree) {
                myFree(order);
            }
        }
        void RegisteFree(FREE f)
        {
            myFree = f;
        }
    
    private:
        FREE myFree;
        unsigned int capacity;
        unordered_map<string, NODE> que;
    };
    
    
    template <typename NODE> class ProQueue : public MyQueue<NODE> {
    public:
        ProQueue()
        {
            this->capacity = DEFAULT_MAX_QUEUE_SIZE;
            myFree = nullptr;
        }
        ProQueue(int capacity)
        {
            this->capacity = capacity;
            myFree = nullptr;
        }
        virtual ~ProQueue()
        {
            while (!this->que.empty()) {
                auto it = this->que.top();
                que.pop();
                MyFree(it);
            }
        }
    
        int Insert(string id, NODE order)
        {
            (void)id;
            if (this->que.size() >= this->capacity) {
                return QUEUE_SIZE_IS_FULL;
            }
            this->que.push(order);
            return 0;
        }
        bool IsEmpty()
        {
            return this->que.empty();
        }
        NODE GetFrontAndPop()
        {
            NODE order = this->que.top();
            this->que.pop();
            return order;
        }
        int Size()
        {
            return this->que.size();
        }
        void MyFree(NODE order)
        {
            if (myFree) {
                myFree(order);
            }
        }
        void RegisteFree(FREE f)
        {
            myFree = f;
        }
    
    private:
        unsigned int capacity;
        FREE myFree;
        priority_queue<NODE, vector<NODE>, MyComparator<NODE>> que;
    };
    
    #endif
    

    dispatch.h

    /*
     * @Author: mayihui
     * @Date: 2022-09-19 20:37:45
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-20 00:15:45
     * @Description: dispatch strategic implement
     *
     */
    
    #ifndef DISPATCH_H
    #define DISPATCH_H
    
    #include <iostream>
    #include "type.h"
    #include "data.h"
    #include "timer.h"
    
    using namespace std;
    
    struct Param {
        MyQueue<Order *> *orders;
        MyQueue<Courier *> *couriers;
        void *timer; // use for close timer
    };
    
    static int Randrange(int min, int max)
    {
        if (max <= min) {
            return -1;
        }
        return min + rand() % (max - min);
    }
    
    class Dispatch : public Notify {
    public:
        Dispatch()
        {
            range = nullptr;
            orders = 0;
            foodwait = 0;
            carieswait = 0;
            srand((unsigned)time(NULL));
        }
        virtual ~Dispatch() {}
    
        virtual int TryDispatchOrder(Order *order, MyQueue<Courier *> *couriers, MyQueue<Order *> *orders) = 0;
        virtual int TryDispatchCourier(Courier *courier, MyQueue<Order *> *orders, MyQueue<Courier *> *couriers) = 0;
        void DeleteOrder(Order *order, MyQueue<Order *> *orders) {
            orders->MyFree(order);
        }
        void DeleteCourier(Courier *courier, MyQueue<Courier *> *couriers) {
            couriers->MyFree(courier);
        }
        int NotifyEvent(int event, void *data)
        {
            int ret = 0;
            Node *node = (Node *)data;
            switch (event) {
                case ORDER_PREPARED:
                    NotifyOrderPrepared((Order *)node->data);
                    ret = TryDispatchOrder((Order *)node->data, ((Param *)node->param)->couriers, ((Param *)node->param)->orders);
                    break;
                case COURIER_ARRIVED:
                    NotifyCourierArrived((Courier *)node->data);
                    ret = TryDispatchCourier((Courier *)node->data, ((Param *)node->param)->orders,
                    ((Param *)node->param)->couriers);
                    break;
                case (DELETE_EVENT | ORDER_PREPARED):
                    DeleteOrder((Order *)node->data, ((Param *)node->param)->orders);
                    break;
                case (DELETE_EVENT | COURIER_ARRIVED):
                    DeleteCourier((Courier *)node->data, ((Param *)node->param)->couriers);
                    break;
                default:
                    cout<<"error event "<<event<<endl;;
            }
    
            if (IsStaties()) {
                Timer *t = (Timer *)((Param *)node->param)->timer;
                cout << "avg food wait time: " << GetAvgFoodWaitTime() << " ms\n";
                cout << "avg couries wait time: " << GetAvgCouriersWaitTime() << " ms\n";
                t->CloseTimer();
            }
    
            return ret;
        }
        void NotifyOrderPrepared(void *data)
        {
            Order *order = (Order *)data;
            cout << "prepare order " << order->id << " ts " << order->prepareTime << endl;
        }
        void NotifyCourierArrived(void *data)
        {
            Courier *courier = (Courier *)data;
            cout << "arrived courier " << courier->courierId << " ts " << courier->arriveTime << endl;
        }
        void SetSize(int size)
        {
            this->size = size;
        }
        bool IsStaties()
        {
            if (size <= orders) {
                return true;
            }
            return false;
        }
        void RegistRand(RANDRANGE rg)
        {
            range = rg;
        }
        int CariesArrivedTime(int min, int max)
        {
            if (range != nullptr) {
                return range(min, max);
            }
            return Randrange(min, max);
        }
        void AddFoodWait(int prepareTime)
        {
            if (prepareTime < 0) {
                cout<<"error: invalid prepareTime: "<<prepareTime<<endl;
                return;
            }
            this->foodwait += prepareTime;
        }
        int64_t GetFoodWait()
        {
            return foodwait;
        }
        void AddCariesWait(int wait)
        {
            if (wait < 0) {
                cout<<"error: invalid wait time: "<<wait<<endl;
                return;
            }
            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 GetAvgCouriersWaitTime()
        {
            if (orders == 0) {
                return 0;
            }
            return carieswait / orders;
        }
    
    private:
        RANDRANGE range;
        int64_t foodwait;
        int64_t carieswait;
        int64_t orders;
        int size;
    };
    
    class Matched : public Dispatch {
    public:
        int TryDispatchOrder(Order *order, MyQueue<Courier *> *couriers, MyQueue<Order *> *orders)
        {
            int ret = 0;
            HashQueue<Courier *> *hs = (HashQueue<Courier *> *)couriers;
            if (hs->IsExist(order->id)) {
                Courier *courier = hs->GetValbyId(order->id);
                AddCariesWait(order->prepareTime - courier->arriveTime);
                AddOrders();
                cout << "[Match] courier " << courier->courierId << " pick up order " << order->id << endl;
                hs->RemoveById(courier->id);
                orders->MyFree(order);
                couriers->MyFree(courier);
                return SUCCESS;
            } else {
                ret = orders->Insert(order->id, order);
                if (ret != 0) {
                    cout<<"error order insert "<<ret<<endl;
                    return 0;
                }
            }
    
            // not find courier
            return COURIER_NOT_ATTRIVED;
        }
        int TryDispatchCourier(Courier *courier, MyQueue<Order *> *orders, MyQueue<Courier *> *couriers)
        {
            int ret = 0;
            HashQueue<Order *> *od = (HashQueue<Order *> *)orders;
            if (od->IsExist(courier->id)) {
                Order *order = od->GetValbyId(courier->id);
                AddFoodWait(courier->arriveTime - order->prepareTime);
                AddOrders();
                cout << "[Match] courier " << courier->courierId << " pick up order " << order->id << endl;
                od->RemoveById(order->id);
                orders->MyFree(order);
                couriers->MyFree(courier);
                return SUCCESS;
            } else {
                ret = couriers->Insert(courier->id, courier);
                if (ret != 0) {
                    cout<<"error couriers insert "<<ret<<endl;
                    return 0;
                }
            }
            return ORDER_NOT_PREPARE;
        }
    };
    
    class FIFO : public Dispatch {
    public:
        int TryDispatchOrder(Order *order, MyQueue<Courier *> *couriers, MyQueue<Order *> *orders)
        {
            int ret = 0;
            ProQueue<Courier *> *hs = (ProQueue<Courier *> *)couriers;
            if (!hs->IsEmpty()) {
                Courier *courier = hs->GetFrontAndPop();
                AddCariesWait(order->prepareTime - courier->arriveTime);
                AddOrders();
                cout << "[FIFO] courier " << courier->courierId << " pick up order " << order->id << endl;
                orders->MyFree(order);
                couriers->MyFree(courier);
                return SUCCESS;
            } else {
                ret = orders->Insert(order->id, order);
                if (ret != 0) {
                    cout<<"error order insert "<<ret<<endl;
                    return 0;
                }
            }
            return COURIER_NOT_ATTRIVED;
        }
        int TryDispatchCourier(Courier *courier, MyQueue<Order *> *orders, MyQueue<Courier *> *couriers)
        {
            int ret = 0;
            ProQueue<Order *> *hs = (ProQueue<Order *> *)orders;
            if (!hs->IsEmpty()) {
                Order *order = hs->GetFrontAndPop();
                AddFoodWait(courier->arriveTime - order->prepareTime);
                AddOrders();
                cout << "[FIFO] courier " << courier->courierId << " pick up order " << order->id << endl;
                orders->MyFree(order);
                couriers->MyFree(courier);
                return SUCCESS;
            } else {
                ret = couriers->Insert(courier->id, courier);
                if (ret != 0) {
                    cout<<"error couriers insert "<<ret<<endl;
                    return 0;
                }
            }
            return ORDER_NOT_PREPARE;
        }
    };
    
    #endif
    

    error

    /*
     * @Author: mayihui
     * @Date: 2022-09-19 20:38:11
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-19 23:15:02
     * @Description: error code in this system
     */
    
    #ifndef ERROR_H
    #define ERROR_H
    
    enum ErrorCode {
        SUCCESS = 0,
        ORDER_NOT_PREPARE,
        COURIER_NOT_ATTRIVED,
        QUEUE_SIZE_IS_FULL,
        QUEUE_ELEMENT_IS_EXIST,
    };
    
    #endif
    

    server

    /*
     * @Author: mayihui
     * @Date: 2022-09-19 20:38:23
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-19 23:51:15
     * @Description: server
     */
    
    #ifndef SERVER_H
    #define SERVER_H
    
    #include <iostream>
    #include <string>
    #include <queue>
    #include <thread>
    #include <chrono>
    #include <limits.h>
    #include <condition_variable>
    #include <fstream>
    #include <unordered_map>
    #include "json/json.h"
    
    #include "type.h"
    #include "data.h"
    #include "dispatch.h"
    #include "timer.h"
    
    using namespace std;
    using namespace chrono;
    
    class Server {
    private:
        // std::condition_variable vals;
        // std::mutex mtx; // 保护
        int64_t capacity;
        int stragegie; // 策略
        Dispatch *dispatch;
        MyQueue<Order *> *orders;
        MyQueue<Courier *> *couriers;
        Timer *timer;
        bool dispatching;
    
    public:
        /* *
         * @description: init server, init the strategic of dispatch order , init the queue of orders and couriers
         * @param {Config} *conf  conf information , include strategic, time
         * @return 0 successed, others error
         * @author: mayihui
         */
        int InitServer(Config *conf);
        /* *
         * @description: free the queue struct of order and courier
         * @return void
         * @author: mayihui
         */
        void DeInitServer();
        /* *
         * @description: register the random function by user, use for product a range rand number
         * @param {RANDRANGE} rnd
         * @return void
         * @author: mayihui
         */
        void RegistRand(RANDRANGE rnd);
        /* *
         * @description: start a thread to read data from file, insert event  node to a timers.
         * @param {char*} file
         * @return 0 successed, others error
         * @author: mayihui
         */
        int ReadData(const char *file);
        /* *
         * @description: dispatch order , start the thread of timers, dispatch the order in timer notification.
         * @return 0 successed, others error
         * @author: mayihui
         */
        int TryDispatchOrder();
        /* *
         * @description: get average courier wait time
         * @return {*}
         * @author: mayihui
         */
        int GetAvgCourierWaitTime();
        /* *
         * @description: get average food wait time
         * @return {*}
         * @author: mayihui
         */
        int GetAvgFoodWaitTime();
        /* *
         * @description:
         * @param {FREE} f for free order
         * @return {*}
         * @author: mayihui
         */
        void RegistOrderFree(FREE f);
        /* *
         * @description:
         * @param {FREE} f for free courier
         * @return {*}
         * @author: mayihui
         */
        void RegistCourierFree(FREE f);
    };
    
    #endif
    

    timer

    /*
     * @Author: mayihui
     * @Date: 2022-09-19 20:43:47
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-19 23:24:49
     * @Description:  use priority queue to implement a simple timer
     */
    
    #ifndef TIMER_H
    #define TIMER_H
    
    #include <chrono>
    #include "type.h"
    using namespace chrono;
    
    #define INTERVAL 500
    
    struct TimerComparator {
        bool operator() (Node *&arg1, Node *&arg2) {
            return arg1->tms > arg2->tms;
        }
    };
    
    class Timer {
    public:
        Timer()
        {
            interval = INTERVAL;
            running = true;
        }
        int32_t SetInterval(int interval)
        {
            this->interval = interval; // ms
            return 0;
        }
        void StartTimer()
        {
            running = true;
        }
        void CloseTimer()
        {
            running = false;
        }
        int32_t InsertNode(Node *node)
        {
            std::lock_guard<std::mutex> guard(mtx);
            que.emplace(node);
            return 0;
        }
        void TimerRun()
        {
            while (running) {
                std::this_thread::sleep_for(std::chrono::milliseconds(interval));
                std::lock_guard<std::mutex> guard(mtx);
                auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
    
                while (!que.empty() && que.top()->tms < now) {
                    Node *t = que.top();
                    t->notify->NotifyEvent(t->event, t);
                    que.pop();
                    cout<<"timer"<<t->id<<endl;
                    delete t;
                }
            }
            // timer exit normally
            while (!que.empty()) {
                Node *d = que.top();
                d->notify->NotifyEvent(d->event | DELETE_EVENT, d);
                que.pop();
                delete d;
            }
        }
    
    private:
        std::mutex mtx;
        priority_queue<Node*, vector<Node*>, TimerComparator> que;
        bool running;
        int interval; // ms
    };
    
    #endif
    

    type

    /*
     * @Author: mayihui
     * @Date: 2022-09-19 20:44:01
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-19 23:35:28
     * @Description: define some type of this system
     */
    
    #ifndef TYPE_H
    #define TYPE_H
    
    #include <iostream>
    #include <string>
    #include <queue>
    #include <thread>
    #include <chrono>
    #include <condition_variable>
    #include "error.h"
    
    using namespace std;
    
    // range random function
    typedef int (*RANDRANGE)(int min, int max);
    
    typedef void (*FREE)(void *data);
    
    // couries information
    struct Courier {
        string id;          // order id
        string courierId;   // self id
        int64_t arriveTime; // courier arrived
        int64_t tms;
        bool operator < (const Courier &co) const
        {
            return arriveTime < co.arriveTime;
        }
        bool operator > (const Courier &co) const
        {
            return arriveTime > co.arriveTime;
        }
    };
    
    // food  information
    struct Food {
        string name;
        int prepareTime;
    };
    
    // order information
    struct Order {
        string id;
        Food food;
        int state;
        int64_t dispatchTime; // dispatch time
        int64_t prepareTime;  // order prepared time
        int64_t tms;
        bool operator < (const Order &od) const
        {
            return prepareTime < od.prepareTime;
        }
        bool operator > (const Order &od) const
        {
            return prepareTime > od.prepareTime;
        }
    };
    
    // timer notify
    class Notify {
    public:
        virtual int NotifyEvent(int event, void *data) = 0;
        virtual ~Notify() {}
    };
    
    // timer node
    struct Node {
        void *data;     //  order or couries data
        void *param;    // user param
        int64_t tms;    // event time
        int event;      // events
        Notify *notify; // notify process
        uint64_t id;    // node inner id
        bool operator < (const Node &node) const
        {
            return tms < node.tms;
        }
        bool operator > (const Node &node) const
        {
            return tms > node.tms;
        }
    };
    
    template <typename NODE> 
    struct MyComparator {
        bool operator() (NODE &arg1, NODE &arg2) {
            return arg1->tms > arg2->tms;
        }
    };
    
    #define ORDER_PREPARED 0x01
    #define COURIER_ARRIVED 0x02
    #define DELETE_EVENT 0x10
    
    enum STRATEGIE {
        STRATEGIE_MATCH = 0x01, // match strategie
        STRATEGIE_FIFO          // fifo strategie
    };
    // config information of server
    struct Config {
        STRATEGIE st;
        int32_t cap;
    };
    
    #define DISPATCH_SIZE_EACH_TIME 2
    #define RAND_MIN_SECOND 3
    #define RAND_MAX_SECOND 15
    #define ONE_SECOND_MS 1000
    #define DISPATCH_INTERVAL 2000 // ms
    
    #endif
    

    server

    /*
     * @Author: mayihui
     * @Date: 2022-09-16 22:52:25
     * @LastEditors: mayihui
     * @LastEditTime: 2022-09-20 00:12:19
     * @Description: implement of server
     */
    
    #include <iostream>
    #include <string>
    #include <queue>
    #include <thread>
    #include <chrono>
    #include <condition_variable>
    #include <fstream>
    #include <unordered_map>
    #include "json/json.h"
    #include "server.h"
    using namespace std;
    using namespace chrono;
    
    static void FreeOrder(Order *order)
    {
        delete order;
    }
    
    static void FreeCourier(Courier *courier)
    {
        delete courier;
    }
    
    
    int Server::TryDispatchOrder()
    {
        timer->StartTimer();
        timer->TimerRun();
        return 0;
    }
    
    int Server::InitServer(Config *conf)
    {
        // default conf
        if (conf == NULL) {
            stragegie = STRATEGIE_MATCH;
            capacity = DEFAULT_MAX_QUEUE_SIZE;
        } else {
            stragegie = conf->st;
            capacity = conf->cap;
        }
    
        if (stragegie == STRATEGIE_MATCH) {
            Matched *match = new Matched();
            dispatch = (Dispatch *)match;
            this->orders = new HashQueue<Order *>();
            this->couriers = new HashQueue<Courier *>();
        } else if (stragegie == STRATEGIE_FIFO) {
            FIFO *fifo = new FIFO();
            dispatch = (Dispatch *)fifo;
            this->orders = new ProQueue<Order *>();
            this->couriers = new ProQueue<Courier *>();
        }
        this->timer = new Timer();
        this->orders->RegisteFree((FREE)FreeOrder);
        this->couriers->RegisteFree((FREE)FreeCourier);
        dispatching = true;
        return 0;
    }
    
    void Server::DeInitServer()
    {
        if (this->dispatch) {
            delete this->dispatch;
        }
        if (this->orders) {
            delete this->orders;
        }
        if (this->couriers) {
            delete this->couriers;
        }
        if (this->timer) {
            this->timer->CloseTimer();
            delete this->timer;
        }
    }
    
    int Server::GetAvgCourierWaitTime()
    {
        return dispatch->GetAvgCouriersWaitTime();
    }
    int Server::GetAvgFoodWaitTime()
    {
        return dispatch->GetAvgFoodWaitTime();
    }
    void Server::RegistRand(RANDRANGE rnd)
    {
        dispatch->RegistRand(rnd);
    }
    
    void Server::RegistOrderFree(FREE f)
    {
        this->orders->RegisteFree(f);
    }
    
    void Server::RegistCourierFree(FREE f)
    {
        this->couriers->RegisteFree(f);
    }
    
    int Server::ReadData(const char *filename)
    {
        Json::Reader reader;
        Json::Value root;
    
        std::ifstream is;
        static int64_t cid = 0;
        static int64_t eventid = 0;
        Param param = {
            this->orders,
            this->couriers,
            NULL,
        };
    
        is.open(filename, std::ios::binary);
        if (reader.parse(is, root, false)) {
            int size = root.size();
            dispatch->SetSize(size);
            for (int i = 0; i < size;) {
                int j = 0;
                for (; j < DISPATCH_SIZE_EACH_TIME && i + j < size;) {
                    Order *order = new Order();
                    Courier *courier = new Courier();
    
                    Json::Value tmp = root[i + j];
                    order->id = tmp["id"].asString();
    
                    order->food.name = tmp["name"].asString();
                    order->food.prepareTime = tmp["prepTime"].asInt() * ONE_SECOND_MS;
                    order->dispatchTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
                    order->prepareTime = order->dispatchTime + order->food.prepareTime;
                    order->tms = order->prepareTime;
    
                    int rnd = dispatch->CariesArrivedTime(RAND_MIN_SECOND, RAND_MAX_SECOND);
                    courier->arriveTime = order->dispatchTime + rnd * ONE_SECOND_MS;
                    courier->courierId = to_string(cid);
                    courier->id = order->id;
                    courier->tms = courier->arriveTime;
                    cid++;
                    Node *orderEvent = new Node();
                    param.timer = this->timer;
    
                    orderEvent->tms = order->prepareTime;
                    orderEvent->data = order;
                    orderEvent->notify = dispatch;
                    orderEvent->event = ORDER_PREPARED;
                    orderEvent->id = eventid++;
                    orderEvent->param = &param;
                    timer->InsertNode(orderEvent);
                    cout << "recive order " << order->id << " ts " << order->dispatchTime<<" need to prepare for "<<
                        order->food.prepareTime / ONE_SECOND_MS<<" s"<< endl;
    
                    Node *courierEvent = new Node();
                    courierEvent->tms = courier->arriveTime;
                    courierEvent->data = courier;
                    courierEvent->notify = dispatch;
                    courierEvent->event = COURIER_ARRIVED;
                    courierEvent->param = &param;
                    courierEvent->id = eventid++;
    
                    timer->InsertNode(courierEvent);
                    cout << "dispatch courier " << courier->courierId << " ts " << order->dispatchTime <<
                        " will be arrive in " << rnd << " s" << endl;
                    j++;
                }
                i += j;
                std::this_thread::sleep_for(std::chrono::milliseconds(DISPATCH_INTERVAL));
            }
        } else {
            cout << "ERROR: open file " << filename << " failed\n";
        }
        cout << "close file \n";
        is.close();
    
        return 0;
    }
    
    

    cmake

    cmake_minimum_required(VERSION 3.16)
    
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
    link_directories(
        ${CMAKE_SOURCE_DIR}/../lib
    )
    add_library(servers STATIC server.cpp)
    
    
    

    test

    #include "gtest/gtest.h"
    #include "json/json.h"
    #include "timer.h"
    #include "server.h"
    
    
    class CoutStr : public Notify {
    public:
      CoutStr() {
        no = 0;
      }
      int NotifyEvent(int event, void *data) {
        Node* p = (Node*)data;
        EXPECT_EQ(no, event);
        no++;
        Timer* timer = (Timer*)p->param;
        if (no == 2) {
          cout<<"close timer\n";
          timer->CloseTimer();
        }
      }
    private:
      int no;
    };
    /*
     test timer
    */
    TEST(Timer, BasicAssertions) {
      Node *node1 = new Node();
      Node *node2 = new Node();
    
      CoutStr cs;
    
      node1->notify = &cs;
      node1->tms = 100;
      node1->event = 0;
    
      node2->notify = &cs;
      node2->tms = 101;
      node2->event = 1;
      
      Timer timer;
      node2->param = &timer;
      timer.SetInterval(50);
      timer.InsertNode(node1);
      timer.InsertNode(node2);
      timer.TimerRun();
    }
    
    // id matched
    TEST(Matched, TryDispatchOrder) {
      Order od;
      od.id = to_string(0);
      od.prepareTime = 10;
    
      Courier c1, c2;
      c1.id = to_string(0);
      c1.arriveTime = 5;
    
      c2.id = to_string(1);
      c2.arriveTime = 0;
      HashQueue<Courier*> hs;
      hs.Insert(c1.id, &c1);
      hs.Insert(c2.id, &c2);
      HashQueue<Order*> ods;
      hs.RegisteFree(NULL);
      ods.RegisteFree(NULL);
    
      Matched mt;
      int ret = mt.TryDispatchOrder(&od, &hs, &ods);
      EXPECT_EQ(ret, 0);
      EXPECT_EQ(mt.GetAvgCouriersWaitTime(), 5);
    }
    
    // fifo matched
    TEST(FIFO, TryDispatchOrder) {
      Order od;
      od.id = to_string(0);
      od.prepareTime = 10;
    
      Courier c1, c2;
      c1.id = to_string(0);
      c1.courierId = to_string(0);
      c1.arriveTime = 5;
      c2.id = to_string(1);
      c2.courierId = to_string(1);
      c2.arriveTime = 0;
      ProQueue<Courier*> hs;
      hs.Insert(c1.id, &c1);
      hs.Insert(c2.id, &c2);
      ProQueue<Order*> ods;
    
      FIFO fi;
      int ret = fi.TryDispatchOrder(&od, &hs, &ods);
      EXPECT_EQ(ret, 0);
      EXPECT_EQ(fi.GetAvgCouriersWaitTime(), 10);
    }
    
    TEST(HashQueue, BaseActions)
    {
      HashQueue<Courier*> sh_couriers(3);
      Courier c1,c2,c3;
      c1.id = to_string(1);
      c2.id = to_string(2);
      c3.id = to_string(2);
      EXPECT_EQ(0, sh_couriers.Insert(c1.id, &c1));
      EXPECT_EQ(0, sh_couriers.Insert(c2.id, &c2));
      EXPECT_EQ(QUEUE_ELEMENT_IS_EXIST, sh_couriers.Insert(c3.id, &c3));
    
      HashQueue<Courier*> couriers(2);
      EXPECT_EQ(0, couriers.Insert(c1.id, &c1));
      EXPECT_EQ(0, couriers.Insert(c2.id, &c2));
      c3.id = to_string(3);
      EXPECT_EQ(QUEUE_SIZE_IS_FULL, couriers.Insert(c3.id, &c3));
    }
    
    // test priority queue
    TEST(ProQueue, BaseActions)
    {
      ProQueue<Courier*> pro_couriers;
      Courier c1,c2,c3;
      c1.id = to_string(1);
      c1.tms = 30;
      c2.id = to_string(2);
      c2.tms = 2;
      c3.id = to_string(2);
      c3.tms = 12;
      EXPECT_EQ(0, pro_couriers.Insert(c1.id, &c1));
      EXPECT_EQ(0, pro_couriers.Insert(c2.id, &c2));
      EXPECT_EQ(0, pro_couriers.Insert(c3.id, &c3));
    
      EXPECT_EQ(0, pro_couriers.IsEmpty());
      Courier *g1 = pro_couriers.GetFrontAndPop();
      EXPECT_EQ(2, g1->tms);
    
      EXPECT_EQ(0, pro_couriers.IsEmpty());
      Courier *g2 = pro_couriers.GetFrontAndPop();
      EXPECT_EQ(12, g2->tms);
    
      EXPECT_EQ(0, pro_couriers.IsEmpty());
      Courier *g3 = pro_couriers.GetFrontAndPop();
      EXPECT_EQ(30, g3->tms);
      EXPECT_EQ(1, pro_couriers.IsEmpty());
    
    
      ProQueue<Order*> pro_orders;
      Order o1,o2,o3;
      o1.id = to_string(1);
      o1.tms = 20;
      o2.id = to_string(2);
      o2.tms = 10;
      o3.id = to_string(3);
      o3.tms = 40;
    
      EXPECT_EQ(0, pro_orders.Insert(o1.id, &o1));
      EXPECT_EQ(0, pro_orders.Insert(o2.id, &o2));
      EXPECT_EQ(0, pro_orders.Insert(o3.id, &o3));
    
      EXPECT_EQ(0, pro_orders.IsEmpty());
      Order *od1 = pro_orders.GetFrontAndPop();
      EXPECT_EQ(10, od1->tms);
    
      EXPECT_EQ(0, pro_orders.IsEmpty());
      Order *od2 = pro_orders.GetFrontAndPop();
      EXPECT_EQ(20, od2->tms);
    
      EXPECT_EQ(0, pro_orders.IsEmpty());
      Order *od3 = pro_orders.GetFrontAndPop();
      EXPECT_EQ(40, od3->tms);
      EXPECT_EQ(1, pro_orders.IsEmpty());
    }
    
    int Rand(int min, int max)
    {
      return 5;
    }
    // test server
    
    int ProductOrder(Server* server, const char* file)
    {
        pthread_setname_np(pthread_self(), "product");
        return server->ReadData(file);
    }
    
    int TryDispatchOrder(Server* server)
    {
        pthread_setname_np(pthread_self(), "dispatch");
        return server->TryDispatchOrder();
    }
    
    TEST(Server, BaseActionsMatch)
    {
        static Config conf;
        conf.st = STRATEGIE_MATCH; // STRATEGIE_MATCH
        static string file = "data1.json"; // 13 3, 5 5
        conf.cap = 10000;
    
        Server *server1 = new Server();
        server1->InitServer(&conf);
        server1->RegistRand((RANDRANGE)Rand);
    
        thread read(ProductOrder, server1, file.c_str());
        thread disp(TryDispatchOrder, server1);
        read.join();
        disp.join();
        EXPECT_EQ(4 * 1000 ,server1->GetAvgCourierWaitTime());
        EXPECT_EQ(1 * 1000 ,server1->GetAvgFoodWaitTime());
        server1->DeInitServer();
        delete server1;
    }
    
    // order  origin 13 3 4 14 12 6  9  8  11
    // courier origin 5 5 5 5  5  5  5  5  5
    
    // order actual  13 3 6 16 16 10 15 14 19
    // courier actual 5 5 7 7  9  9  11 11 13
    
    // match food       2 1                    -> 3000 / 9 ms
    // match courier 8      9 7   1  4  3  6   -> 4222 ms
    
    
    // match
    TEST(Server, BaseActionsMatch1)
    {
        static Config conf;
        conf.st = STRATEGIE_MATCH; // STRATEGIE_MATCH
        static string file = "data2.json"; 
    
        conf.cap = DEFAULT_MAX_QUEUE_SIZE;
    
        Server server1;
        server1.InitServer(&conf);
        server1.RegistRand((RANDRANGE)Rand);
    
        thread read(ProductOrder, &server1, file.c_str());
        thread disp(TryDispatchOrder, &server1);
        read.join();
        disp.join();
        EXPECT_EQ(4222 ,server1.GetAvgCourierWaitTime());
        EXPECT_EQ(333 ,server1.GetAvgFoodWaitTime());
        server1.DeInitServer();
    }
    // order  origin 13 3 4 14 12 6  9  8  11
    // courier origin 5 5 5 5  5  5  5  5  5
    
    // order actual  13 3 6 16 16 10 15 14 19
    // courier actual 5 5 7 7  9  9  11 11 13
    
    // fifo   order   3 6 10 13 14 15 16 16 19
    // fifo   courier 5 5 7  7  9  9  11 11 13
    // food wait :    2                         -> 2000 / 9 ms
    // courier wait:    1 3  6  5  6  5  5  6   -> 4111 ms
    TEST(Server, BaseActionsFIFO1)
    {
        static Config conf;
        conf.st = STRATEGIE_FIFO;
        static string file = "data2.json"; 
    
        conf.cap = DEFAULT_MAX_QUEUE_SIZE;
    
        Server *server1 = new Server();
        server1->InitServer(&conf);
        server1->RegistRand((RANDRANGE)Rand);
    
        thread read(ProductOrder, server1, file.c_str());
        thread disp(TryDispatchOrder, server1);
        read.join();
        disp.join();
        EXPECT_EQ(4111 ,server1->GetAvgCourierWaitTime());
        EXPECT_EQ(222 ,server1->GetAvgFoodWaitTime());
        server1->DeInitServer();
        delete server1;
    }
    
    // 13   3
    // 5 5
    TEST(Server, BaseActionsFIFO)
    {
        static Config conf;
        conf.st = STRATEGIE_FIFO; // STRATEGIE_FIFO
        static string file = "data1.json"; // 13 3 , 5 5
        conf.cap = 10000;
    
        Server *server = new Server();
        server->InitServer(&conf);
        server->RegistRand((RANDRANGE)Rand);  // arrived 0
    
        thread read(ProductOrder, server, file.c_str());
        thread disp(TryDispatchOrder, server);
        read.join();
        disp.join();
        EXPECT_EQ(4 * 1000 ,server->GetAvgCourierWaitTime());
        EXPECT_EQ(1 * 1000 ,server->GetAvgFoodWaitTime());
        server->DeInitServer();
        delete server;
    }
    
    
    

    data1.json

    [
        {
            "id": "58e9b5fe-3fde-4a27-8e98-682e58a4a65d", 
            "name": "McFlury", 
            "prepTime": 13
        }, 
        {
            "id": "2ec069e3-576f-48eb-869f-74a540ef840c", 
            "name": "Acai Bowl", 
            "prepTime": 3
        }
    ]
    

    data2.json

    [
        {
            "id": "58e9b5fe-3fde-4a27-8e98-682e58a4a65d", 
            "name": "McFlury", 
            "prepTime": 13
        }, 
        {
            "id": "2ec069e3-576f-48eb-869f-74a540ef840c", 
            "name": "Acai Bowl", 
            "prepTime": 3
        },
        {
            "id": "a8cfcb76-7f24-4420-a5ba-d46dd77bdffd", 
            "name": "Banana Split", 
            "prepTime": 4
        }, 
        {
            "id": "58e9b5fe-3fde-4a27-8e98-682e58a4a66d", 
            "name": "McFlury", 
            "prepTime": 14
        }, 
        {
            "id": "2ec069e3-576f-48eb-869f-74a540ef840c", 
            "name": "Acai Bowl", 
            "prepTime": 12
        }, 
        {
            "id": "690b85f7-8c7d-4337-bd02-04e04454c826", 
            "name": "Yogurt", 
            "prepTime": 6
        }, 
        {
            "id": "972aa5b8-5d83-4d5e-8cf3-8a1a1437b18a", 
            "name": "Chocolate Gelato", 
            "prepTime": 9
        }, 
        {
            "id": "c18e1242-0856-4203-a98c-7066ead3bd6b", 
            "name": "Cobb Salad", 
            "prepTime": 8
        }, 
        {
            "id": "66a2611c-9a93-4ccd-bb85-98f423247bf9", 
            "name": "Cottage Cheese", 
            "prepTime": 11
        }
    ]
    
    

    cmake

    cmake_minimum_required(VERSION 3.16)
    project(SERVER)
    set(CMAKE_BUILD_TYPE Debug)
    include_directories(
        ${CMAKE_SOURCE_DIR}/../
        ${CMAKE_SOURCE_DIR}/include
        ${CMAKE_SOURCE_DIR}/../include
    )
    set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    
    link_directories(
        ${CMAKE_SOURCE_DIR}/../lib
    )
    
    aux_source_directory(. DIR_SRCS)
    
    message(${CMAKE_SOURCE_DIR})
    
    add_executable(Test ${DIR_SRCS})
    
    target_link_libraries(Test PUBLIC -lservers -lpthread -ljsoncpp ${CMAKE_SOURCE_DIR}/../lib/libgtest.a ${CMAKE_SOURCE_DIR}/../lib/libgtest_main.a)
    
    #include "server.h"
    
    
    int ProductOrder(Server* server, const char* file)
    {
    #ifdef __GNUC__
        pthread_setname_np(pthread_self(), "product");
    #endif
        return server->ReadData(file);
    }
    
    int TryDispatchOrder(Server* server)
    {
    #ifdef __GNUC__
        pthread_setname_np(pthread_self(), "dispatch");
    #endif
        return server->TryDispatchOrder();
    }
    
    int main(int argc, const char* argv[])
    {
        Config conf;
        conf.st = STRATEGIE_FIFO; // STRATEGIE_FIFO
        string file = "data.json";
        if (argc ==  3) {
            conf.st = (STRATEGIE)atoi(argv[1]);
            file = argv[2];
        }
    
        if (conf.st != STRATEGIE_MATCH && conf.st != STRATEGIE_FIFO) {
            cout<<"error stragegie : "<<conf.st<<endl;
            exit(0);
        }
    
        conf.cap = DEFAULT_MAX_QUEUE_SIZE;
    
        Server server;
        server.InitServer(&conf);
    
        thread read(ProductOrder, &server, file.c_str());
        thread disp(TryDispatchOrder, &server);
        read.join();
        disp.join();
        server.DeInitServer();
    }
    

    cmake

    cmake_minimum_required(VERSION 3.16)
    project(SERVER)
    set(CMAKE_BUILD_TYPE Debug)
    set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    include_directories(
        ${CMAKE_SOURCE_DIR}/include
    )
    
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror")
    #target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror)
    
    link_directories(
        ${CMAKE_SOURCE_DIR}/lib
    )
    add_subdirectory(src)
    
    aux_source_directory(. DIR_SRCS)
    
    add_executable(Server ${DIR_SRCS})
    
    target_link_libraries(Server PUBLIC servers -lpthread -ljsoncpp -lgtest)
    

    相关文章

      网友评论

          本文标题:2022-09-20

          本文链接:https://www.haomeiwen.com/subject/ussvortx.html