zoukankan      html  css  js  c++  java
  • vc中ui线程和工作线程协调通讯的朴素实现方式

    当要处理一些比较耗时的任务时, 一般是把这些任务放到一个工作线程中去执行, 否则会阻塞界面的响应, 导致用户体验差....

    所以经常会用到线程

    从任务角度上看, 线程大致分两类, 界面线程(UI线程, 一般由主线程充当); 工作线程(有UI线程创建, 根据生命周期, 可再细分为长期线程和临时线程)

    vc中, 创建线程可以通过多种方式, 这里说

    线程就是一个可以和其他线程"并发"执行的函数, 一个随便写的例子:

    unsigned __stdcall _netWorkThread(void *pVoid)
    {
        cout << "network thread running" <<endl;
        NetWorkThread* pNetWork = reinterpret_cast<NetWorkThread*>(pVoid);
    
        HANDLE events[] = {pNetWork->QuitEvent(), pNetWork->ConnEvent(), pNetWork->SendEvent()};
        bool bRun = true;
        while(bRun)
        {
            DWORD dwRet = ::WaitForMultipleObjects(sizeof(events) / sizeof(events[0]), events, FALSE, pNetWork->EventTimeOut());
            switch(dwRet)
            {
            case WAIT_TIMEOUT:            //等待超时
                cout << "time out" <<endl;
                break;
            case WAIT_FAILED:            //错误
                //GetLastError();
                break;
            case WAIT_OBJECT_0:            //退出事件
                bRun = false;
                break;
            case WAIT_OBJECT_0 + 1:        //连接事件
                if(!pNetWork->TaskConn())
                {
                    pNetWork->FeedBack()->ConnFailed();
                }
                break;
            case WAIT_OBJECT_0 + 2:        //发送数据包事件
                break;
            }
        }
    
        cout << "network thread quit" <<endl;
        return 0;
    }
    _netWorkThread函数是全局函数(不知道如何封装成一个成员函数)

    class NetWorkThread
    {
    public:
        NetWorkThread();
        virtual ~NetWorkThread();
    
        bool run(IFeedBack* iFeedBack);
    
        HANDLE& QuitEvent();
        HANDLE& ConnEvent();
        HANDLE& SendEvent();
        int EventTimeOut();
    
        void Conn(CString ip, unsigned short port);
        void Quit();
        CString ServerIP();
        unsigned short ServerPort();
    
        //只被工作线程调用, Task前缀
        bool TaskConn();
    
        //反馈工作线程执行结果的接口对象
        IFeedBack* FeedBack();
    
    private:
        bool CheckEvent();        //检测事件是否正确
    
    
    private:
        HANDLE hQuitEvent;        //退出线程事件
        HANDLE hConnEvent;        //连接服务器事件
        HANDLE hSendEvent;        //发送数据包事件
        int eventTimeOut;        //事件超时(单位毫秒)
        
        
        HANDLE hThread;            //线程句柄
    
    
        SOCKET sock;            //连接套接字
        CString serverIP;        //服务器ip
        unsigned short serverPort;    //服务器端口
    
        IFeedBack* iFeedBack;    //ui线程接口
    };
    NetWorkThread::NetWorkThread(): 
        eventTimeOut(10000), 
        sock(INVALID_SOCKET), 
        iFeedBack(0)
    {
        WSADATA wsaData;
    
        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if(iResult != NO_ERROR)
        {
            cout << "WSAStartup Error" <<endl;
        }
        hQuitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        hConnEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        hSendEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    }
    
    bool NetWorkThread::CheckEvent()
    {
        if(    NULL == hQuitEvent ||
            NULL == hConnEvent ||
            NULL ==    hSendEvent)
            return false;
        return true;
    }
    
    NetWorkThread::~NetWorkThread()
    {
        if(NULL != hQuitEvent)
            CloseHandle(hQuitEvent);
        if(NULL != hConnEvent)
            CloseHandle(hConnEvent);
        if(NULL != hSendEvent)
            CloseHandle(hSendEvent);
    }
    
    bool NetWorkThread::run(IFeedBack* iFeedBack)
    {
        if(!CheckEvent())
            return false;
    
        this->iFeedBack = iFeedBack;
        
        unsigned uRet;
        hThread = (HANDLE)_beginthreadex(0, 0, _netWorkThread, this, 0, &uRet);
        if(0 == hThread)
        {
            return false;
        }
        return true;
    }
    
    HANDLE& NetWorkThread::QuitEvent()
    {
        return this->hQuitEvent;
    }
    
    HANDLE& NetWorkThread::ConnEvent()
    {
        return this->hConnEvent;
    }
    
    HANDLE& NetWorkThread::SendEvent()
    {
        return this->hSendEvent;
    }
    int NetWorkThread::EventTimeOut()
    {
        return this->eventTimeOut;
    }
    
    void NetWorkThread::Conn(CString ip, unsigned short port)
    {
        this->serverIP = ip;
        this->serverPort = port;
        SetEvent(this->hConnEvent);
    }
    void NetWorkThread::Quit()
    {
        SetEvent(this->hQuitEvent);
    }
    CString NetWorkThread::ServerIP()
    {
        return this->serverIP;
    }
    unsigned short NetWorkThread::ServerPort()
    {
        return this->serverPort;
    }
    
    bool NetWorkThread::TaskConn()
    {
        sockaddr_in addr_in;
        addr_in.sin_family = AF_INET;
        addr_in.sin_addr.s_addr = inet_addr(this->serverIP.GetBuffer(0));
        addr_in.sin_port = htons(this->serverPort);
    
        this->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(INVALID_SOCKET == this->sock)
        {
            cout << "call socket function error:" << WSAGetLastError() <<endl;
            return false;
        }
        
        int ret = connect(this->sock, (sockaddr*)&addr_in, sizeof(addr_in));
        if(SOCKET_ERROR == ret)
        {
            cout << "WSaGetLastError:" << WSAGetLastError() <<endl;
            return false;
        }
        return true;
    }
    
    IFeedBack* NetWorkThread::FeedBack()
    {
        return this->iFeedBack;
    }

    写着写着, 不知道要写什么了, 晕~~~~~~~~

    思路:

    UI线程到工作线程的消息传递, 可以通过 封装队列, 加个事件触发功能

    工作线程到UI线程的反馈, 可以是UI线程先继承一个接口并实现这些接口, 工作线程保存UI线程对象的接口类型指针, 当UI线程要反馈消息到UI线程时候, 就可以通过这个指针对象调用接口方法, 这样UI界面就可以反馈结果给用户

    这样做可能存在危险, 因为这个反馈的动作是工作线程调用的, 如果此时UI线程也同样要操作界面, 就会造成线程间数据冲突了, 要做同步的话, 就得考虑不要卡主UI线程..........

    T____T

  • 相关阅读:
    重新开始学习javase_对象的摧毁
    昨天一日和彭讨论post请求数据的问题
    昨天在公司加班,上午好像就是弄一个ftp的linux服务问题
    昨天有是发现一个新的技术问题
    昨天下午快要下班的时候让他们东软测试
    昨天也没有和家里通话,把时间给了一位同事
    早上8:45到达
    又是一个月初
    今天是下雨天
    从每天开始在工作上才算有点事情
  • 原文地址:https://www.cnblogs.com/jianc/p/2874351.html
Copyright © 2011-2022 走看看