文本纠错项目一些问题

来源:互联网 发布:高校法学教学软件 编辑:程序博客网 时间:2024/06/06 09:56

线程启动问题

  • thread thread_run头文件
namespace THREAD{    class CThread_RUN    {        public:            virtual void run()=0;            virtual void set_cache(hash_record* m_cache)=0;            virtual void set_log(LOG_SYSTEM::Log_system* log)=0;    };    class CThread    {        public:            CThread():m_cache(HASH_BASE){}            CThread(LOG_SYSTEM::Log_system* log):m_log(log){}            void start(CThread_RUN* arg);            hash_record* get_record();            void set_log(LOG_SYSTEM::Log_system* log);        private:            pthread_t m_tid;            hash_record m_cache;            LOG_SYSTEM::Log_system* m_log;            static void* thread_func(void* obj);    };}
  • thread thread_run函数定义
namespace THREAD{    void CThread::start(CThread_RUN* arg)    {        arg->set_log(m_log);        arg->set_cache(&m_cache);        pthread_create(&m_tid,NULL,thread_func,(void*)arg);    }    hash_record* CThread::get_record()    {        return &m_cache;    }    void CThread::set_log(LOG_SYSTEM::Log_system* log)    {        m_log=log;    }    void* CThread::thread_func(void* obj)    {        pthread_detach(pthread_self());        CThread_RUN* obj1=(CThread_RUN*)obj;        obj1->run();//这个地方用到了多态,传入的是CRun的子类,执行的是子类的run函数。    }}
  • thread thread_run关系图
    ![Alt text](./屏幕快照 2015-04-10 下午3.42.26.png)

缓存和日志系统对象指针传参问题

图中三种派生类的对象指针传入start代表启动的就是某个具体的线程,而缓存word_cache(文本纠错的查询结果)则是在启动线程的时候通过线程对象指针调用自己的set_cache设置的,而日志系统指针也是在这个时候传入的。
* thread_run类的结构
* 头文件
“`C++
class CTask_excute:public QUEUE::CQueue::CTask
{
public:
CTask_excute(WORD_CORRECT::CWord_correct& correct,MY_SOCKET::My_socket& info);
std::string excute(hash_record* m_cache,LOG_SYSTEM::Log_system* log);
int send_msg(const char* msg,LOG_SYSTEM::Log_system* log);
void socket_init(LOG_SYSTEM::Log_system* log);
private:
WORD_CORRECT::CWord_correct& m_correct;
MY_SOCKET::My_socket& m_info;
int client_sock;
};
class CRun:public THREAD::CThread_RUN
{
public:
CRun(QUEUE::CQueue* pq);
void run();
void set_log(LOG_SYSTEM::Log_system* log);
void set_cache(hash_record* cache);
private:
QUEUE::CQueue* m_pq;
hash_record* m_cache;
LOG_SYSTEM::Log_system* m_log;
};
class Cache:public THREAD::CThread_RUN
{
public:
Cache(THREADPOOL::CThread_pool& pool);
void run();
void set_cache(hash_record* cache);
void set_log(LOG_SYSTEM::Log_system* log);
void cache_out();
void read_disk_cache();
void write_disk_cache();

    private:        hash_record* m_cache;        const std::string& m_cache_path;        std::vector<THREAD::CThread>& m_thread_vector;        LOG_SYSTEM::Log_system* m_log;};```

派生类都要覆写所有虚基类的全部虚函数,通过虚基类的set_cache,set_log两个方法就可以把缓存日志系统和缓存传进来只能传指针,不能传引用,因为这就是由thread_run启动thread的特性决定的。

线程池启动各种线程

线程池中有两种线程,一种是工作线程,一种是缓存线程,启动线程之前要把一些初始参数设置好,比如说cache,log,就是在线程池中通过start启动的。
* 函数定义

    class CThread_pool    {        public:        CThread_pool(const std::string& cache_path,LOG_SYSTEM::Log_system* log);        void on(THREAD::CThread_RUN* thread_run,THREAD::CThread_RUN* thread_cache);        void off();        std::vector<THREAD::CThread>& get_thread_vector();        ~CThread_pool(){}        QUEUE::CQueue m_que;        const std::string& m_cache_path;        private:        bool m_flag;        std::vector<THREAD::CThread> m_thread_pool;        THREAD::CThread Cache_thread;        CThread_pool(const CThread_pool& obj);        CThread_pool& operator=(const CThread_pool& obj);    };
  • 函数体
 CThread_pool::CThread_pool(const std::string& cache_path,LOG_SYSTEM::Log_system* log):m_cache_path(cache_path),m_thread_pool(THREAD_NUM),m_que(QUEUE_CAPACITY),Cache_thread(log)    {        std::vector<THREAD::CThread>::iterator iter=m_thread_pool.begin();        for(iter;iter!=m_thread_pool.end();iter++)        {            iter->set_log(log);        }    }    void  CThread_pool::on(THREAD::CThread_RUN* thread_run,THREAD::CThread_RUN* thread_cache)    {        if(m_flag==false)        {            m_flag=true;        }        Cache_thread.start(thread_cache);        std::vector<THREAD::CThread>::iterator iter=m_thread_pool.begin();        for(iter;iter!=m_thread_pool.end();iter++)        {            iter->start(thread_run);        }    }    void  CThread_pool::off()    {        if(m_flag==true)        {            m_flag=false;        }    }    std::vector<THREAD::CThread>&  CThread_pool::get_thread_vector()    {        return m_thread_pool;    }

线程池中一个on函数其实就是调用thread中的start的函数来启动线程而线程是个活动的实体,一旦启动就传入不了任何参数,除非将m_log和cache作为引用和指针传入任务参数,所以必须在线程启动时打包处理所有的初始化工作。thread thread_run理解困难根本在于以前的类的初始化工作在一个类的创建的时候就可以解决,thread_run则必须通过另外一个平台类来初始化,和启动。

购物篮问题参照理解

购物篮问题和线程池问题其实本质还是虚基类和虚函数等多态问题的衍生和演化,如果大家能从本质上将这两类问题参照理解对比,基本可以掌握这个难点知识,在大量的代码训练的过程中逐渐参悟了理解这个原理。
* 购物篮类

class Object{    public:        ~Object(){}    virtual void show()=0;    virtual Object* clone()=0;};class Handle{    public:        Handle(Object* obj=NULL):m_ptr(obj){}        Object* operator->()        {            return m_ptr->clone();        }        Object& operator*()        {            return *(m_ptr->clone());        }    private:        Object* m_ptr;};class Phone:public Object{    public:        Phone(std::string brand="",std::string system=""):m_brand(brand),m_system(system){}        void show()        {            std::cout<<"brand: "<<m_brand<<" m_system:"<<m_system<<std::endl;        }        Object* clone()        {            return this;        }    private:        std::string m_brand;        std::string m_system;};class Pad:public Object{    public:        Pad(std::string brand="",double size=0):m_brand(brand),m_size(size){}        void show()        {            std::cout<<"brand: "<<m_brand<<" m_size: "<<m_size<<std::endl;        }        Object* clone()        {            return this;        }    private:        std::string m_brand;        double m_size;};class Book:public Object{    public:    Book(std::string name="",int price=0):m_name(name),m_price(price){}    void show()    {        std::cout<<"book_name : "<<m_name<<" price :"<<m_price<<std::endl;    }    Object* clone()    {        return this;    }    private:    std::string m_name;    int m_price;};typedef std::vector<Handle> Basket;typedef std::vector<Handle>::iterator curse;
  • 测试用例
int main(int argc,char** argv){    Phone iphone5s("apple","IOS8");    Phone mi4("xiaomi","MIUIV6");    Pad ipadair("ipad",9.7);    Pad mipad("mPad",7.9);    Book b1("C++ prime",59);    Book b2("Unix",68);    Basket basket;    basket.push_back(&iphone5s);    basket.push_back(&mi4);    basket.push_back(&ipadair);    basket.push_back(&mipad);    basket.push_back(&b1);    basket.push_back(&b2);    curse iter=basket.begin();    for(iter;iter!=basket.end();iter++)    {        //(*iter).operator->()->show();        (*iter)->show();    }}
  • 用一个篮子可以放进去所有的handle类指针,handle类里就是存放object的派生类指针,购物篮的本质就是不同的类型能放进去一个篮子同时还要能通过相应的函数取出来,所以就有了句柄类,句柄类的作用就是通过函数将派生类的对象指针取出来。
  • thread thread_run的本质有点类似航母甲板上弹射舰载机不管什么类型的舰载机只要符合弹射器的接口,就可以放在弹射器的跑道,将其弹射出去,thread 可以理解称为航母甲板start就是那个弹射器,thread_run就是那个舰载机f18,f15,f14等等都可以,而thread_pool可以就理解为一个航母系统。

任务打包封装

  • Task任务类

    • 头文件

      class CTask_excute:public QUEUE::CQueue::CTask{    public:        CTask_excute(WORD_CORRECT::CWord_correct& correct,MY_SOCKET::My_socket& info);        std::string excute(hash_record* m_cache,LOG_SYSTEM::Log_system* log);        int send_msg(const char* msg,LOG_SYSTEM::Log_system* log);        void socket_init(LOG_SYSTEM::Log_system* log);    private:        WORD_CORRECT::CWord_correct& m_correct;        MY_SOCKET::My_socket& m_info;        int client_sock;};
    • 函数定义,excute()函数

      std::string CTask_excute::excute(hash_record* m_cache,LOG_SYSTEM::Log_system* m_log){    std::string result;    if((*m_cache).count(m_info.m_search)>0)    {        m_log->notice("run thread's hash_map cache has result,return answer to client directly");        result=(*m_cache)[m_info.m_search];    }    else    {        m_log->notice("run thread's hash_map cache no result,go to hash_map index of dic for answer");        result=m_correct(m_info.m_search);        std::pair<std::string,std::string> apair=make_pair(m_info.m_search,result);        (*m_cache).insert(apair);    }    socket_init(m_log);    send_msg(result.c_str(),m_log);    return result;}

    上述代码其实就是将查询词和socket地址等信息和处理文本纠错的类的引用打包成一个类对象,放入工作队列中,其实每个任务类Task的对象都有自己执行的能力,只是通过线程将其从队列中取出来。

0 0
原创粉丝点击