異步任務線程封裝筆記

Task.h

namespace ASYN_WORK
{

    class CTask
    {
    public:
	   CTask(void);
	   virtual ~CTask(void);
	   virtual void Do();
	   virtual void Cancel();
    };

}

Task.cpp

#include "Task.h"
namespace ASYN_WORK
{
    CTask::CTask(void){}
    CTask::~CTask(void){}
    void CTask::Do(){}
    void CTask::Cancel(){}
}

TaskProxy.h

#pragma once
#include <mutex>
#include <thread>
#include <chrono>
#include <functional>
#include "Task.h"

namespace ASYN_WORK
{
    class CTaskProxy : public CTask
    {
    public:

	CTaskProxy(const std::function<void()>& fn);
    void Do()override;
    void Cancel()override;
    void CancelWithoutDoTask();
	~CTaskProxy();
public:
	void Control(bool canWork);

private:
    std::function<void()> m_fn;
    std::mutex m_mutexWork;
	bool m_canWork;
	bool m_cancelWithoutDoTask;
};
}

TaskProxy.cpp

#include "TaskProxy.h"
namespace ASYN_WORK
{

    CTaskProxy::CTaskProxy(const std::function<void()>& fn)
        :m_fn(fn)
        , m_canWork(true)
		, m_cancelWithoutDoTask(false)
    {
    }

    CTaskProxy::~CTaskProxy()
    {
    }

	void CTaskProxy::CancelWithoutDoTask()
	{
		m_cancelWithoutDoTask = true;
	}

    void CTaskProxy::Control(bool canWork)
    {
        std::unique_lock<std::mutex> lock(m_mutexWork);
	    m_canWork = canWork;
    }

    void CTaskProxy::Do()
    {
        std::unique_lock<std::mutex> lock(m_mutexWork);
	    if (!m_canWork)
	    {
		   return;
	    }

	    if (m_fn)
	    {
		   m_fn();//不要在m_fn裏面調用Control
	    }
    }

    void CTaskProxy::Cancel()
    {
		if (!m_cancelWithoutDoTask)
		{
			Do();
		}
    }
}

TaskQueue.h

#pragma once
#include <queue>
#include <mutex>

namespace ASYN_WORK
{
    template<typename T>
    class CTaskQueue
    {
    public:
	   CTaskQueue(void){}
	   ~CTaskQueue(void){}
    public:
	   void Push(const T& t)
	   {
           std::unique_lock<std::mutex> lock(m_mutexTask);
		   m_queueTask.push(t);
	   }

	   bool Pop(T& t)
	   {
           std::unique_lock<std::mutex> lock(m_mutexTask);
		  if (!m_queueTask.empty())
		  {
			 t = m_queueTask.front();
			 m_queueTask.pop();
			 return true;
		  }
		  return false;
	   }

	   void Swap(std::queue<T>& queueTask)
	   {
           std::unique_lock<std::mutex> lock(m_mutexTask);
           m_queueTask.swap(queueTask);
	   }

	   unsigned int Size()
	   {
           std::unique_lock<std::mutex> lock(m_mutexTask);
		   return m_queueTask.size();
	   }
    private:
	   std::queue<T> m_queueTask;
       std::mutex m_mutexTask;
    };
}

WorkEvent.h

#pragma once
#include <mutex>
#include <condition_variable>

namespace ASYN_WORK
{
    class CWorkEvent
    {
    public:
	   CWorkEvent();
	   ~CWorkEvent();
    public:
	   void SetEvent();
	   void WaitEvent();
	   void WaitEvent(const unsigned long long llTime);//ms
	   void ResetEvent();
    private:
        std::condition_variable m_conditionWake;
        std::mutex m_mutexWake;
	    bool m_bWake;
    }; 
}

WorkEvent.cpp

#include "WorkEvent.h"
namespace ASYN_WORK
{
    CWorkEvent::CWorkEvent()
	   :m_bWake(false)
    {
    }

    CWorkEvent::~CWorkEvent()
    {
    }

    void CWorkEvent::SetEvent()
    {
        std::unique_lock<std::mutex> lock(m_mutexWake);	 
        if (!m_bWake)
        {
            m_bWake = true;
            m_conditionWake.notify_one();
        }   
    }

    void CWorkEvent::WaitEvent()
    {
        std::unique_lock<std::mutex> lock(m_mutexWake);
        m_conditionWake.wait(lock, [&](){ return m_bWake; });
	    m_bWake = false;
    }

    void CWorkEvent::WaitEvent(const unsigned long long llTime)
    {
        std::unique_lock<std::mutex> lock(m_mutexWake);
        if (m_conditionWake.wait_for(lock, std::chrono::milliseconds(llTime), [&](){ return m_bWake; }))
        {
            m_bWake = false;
        }
    }
    
    void CWorkEvent::ResetEvent()
    {
        std::unique_lock<std::mutex> lock(m_mutexWake);
	    m_bWake = false;
    }
}

Asyn_Thread.h

#pragma once
#include "WorkEvent.h"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>

namespace ASYN_WORK
{
    class CThread
    {
    public:
	   CThread(void);
	   ~CThread(void);
    public:
	   virtual void Start();
	   virtual void Stop();
    protected:
	   virtual void Run() = 0;
	   bool m_bExit;
	   CWorkEvent m_workEvent;
    private:
        std::thread* m_pThread;
    };
}

Asyn_Thread.cpp

#include "Asyn_Thread.h"
#ifdef __linux__
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#endif

namespace ASYN_WORK
{
    CThread::CThread(void)
	   :m_bExit(false)
	   , m_pThread(nullptr)
    {
    }

    CThread::~CThread(void)
    {
    }

    void CThread::Start()
    {
	   m_bExit = false;
	   m_workEvent.ResetEvent();
       m_pThread = new std::thread(std::bind(&CThread::Run, this));
#ifdef __linux__
	   auto handle = m_pThread->native_handle();
	   std::string tName = MODULE_NAME + std::string("CTh");
	   LOG_DEBUG("thread %d --- with name %s", handle, tName.c_str());
	   pthread_setname_np(handle, tName.c_str());
#endif  
    }

    void CThread::Stop()
    {
	   if (m_bExit)
	   {
		  return;
	   }

	   m_bExit = true;
	   m_workEvent.SetEvent();
	   if (m_pThread)
	   {
		  m_pThread->join();
		  delete m_pThread;
		  m_pThread = nullptr;
	   }
    }
}

ThreadWorker.h

#pragma once
#include <memory>
#include "Asyn_Thread.h"
#include "Task.h"
#include "TaskQueue.h"

namespace ASYN_WORK
{
    class CThreadWorker :
	   public ASYN_WORK::CThread
    {
    public:
	   CThreadWorker(void);
	   ~CThreadWorker(void);
       void PostTask(const std::shared_ptr<CTask>& pTask);
	   void DoTask();
    private:
	   void Run(void);
	   void Cancel();
    private:
        std::queue<std::shared_ptr<CTask> > m_taskQueue;
        CTaskQueue<std::shared_ptr<CTask> > m_incomingTaskQueue;
    };
}

ThreadWorker.cpp

#include "ThreadWorker.h"

namespace ASYN_WORK
{
    CThreadWorker::CThreadWorker(void)
    {
    }

    CThreadWorker::~CThreadWorker(void)
    {
	   CThread::Stop();
    }

    void CThreadWorker::Run(void)
    {
	   while (!m_bExit)
	   {
		  m_workEvent.WaitEvent();
		  DoTask();
	   }
	   Cancel();
    }

    void CThreadWorker::DoTask()
    {
	   m_incomingTaskQueue.Swap(m_taskQueue);
	   while (!m_taskQueue.empty())
	   {
           std::shared_ptr<CTask> pTask = nullptr;
		   pTask = m_taskQueue.front();
		   m_taskQueue.pop();
		   if (pTask)
		   {
			  pTask->Do();
		   }

		   if (m_bExit)
		   {
			  break;
		   }
	   }
    }

    void CThreadWorker::Cancel()
    {
        std::shared_ptr<CTask> pTask = nullptr;
	    while (!m_taskQueue.empty())
	    {
		   pTask = m_taskQueue.front();
		   m_taskQueue.pop();
		   if (pTask)
		   {
			  pTask->Cancel();
		   }
	    }

	   while (m_incomingTaskQueue.Pop(pTask))
	   {
		  if (pTask)
		  {
			 pTask->Cancel();
		  }
	   }
    }
    void CThreadWorker::PostTask(const std::shared_ptr<CTask>& pTask)
    {
        if (pTask)
        {
            m_incomingTaskQueue.Push(pTask);
            m_workEvent.SetEvent();
        }
    }
}

TaskHelper.h

#pragma once
#include "ThreadWorker.h"
#include <mutex>
using namespace std;
using namespace ASYN_WORK;

class TaskHelper
{
public:
	TaskHelper();
	~TaskHelper();
private:
	static TaskHelper* _instance;
	CThreadWorker* m_pThread;
    static mutex m_mutex;
	
public:
	static TaskHelper* Instance();
    void PostTask(const std::shared_ptr<CTask>& pTask);
};

TaskHelper.cpp

#include "TaskHelper.h"

TaskHelper* TaskHelper::_instance = nullptr;
mutex TaskHelper::m_mutex;

TaskHelper::TaskHelper()
	: m_pThread(nullptr)
{
	m_pThread = new CThreadWorker();
	m_pThread->Start();
}


TaskHelper::~TaskHelper()
{
	if (m_pThread != nullptr)
	{
		delete m_pThread;
		m_pThread = nullptr;
	}
}

TaskHelper* TaskHelper::Instance()
{
	unique_lock<mutex> lock(m_mutex);
    if (_instance == nullptr)
	{
		_instance = new TaskHelper();
	}
	return _instance;
}

void TaskHelper::PostTask(const std::shared_ptr<CTask>& pTask)
{
    if (m_pThread != nullptr)
    {
        m_pThread->PostTask(pTask);
    }
}

main.cpp

#include "TaskProxy.h"
#include "TaskHelper.h"
#include<iostream>
void DoJob()
{	
	std::cout << "Do job" << std::endl;
	return;
}

int main(void)
{
	shared_ptr<CTaskProxy> m_taskProxy;
	m_taskProxy = std::make_shared<ASYN_WORK::CTaskProxy>(std::bind(&DoJob));
	TaskHelper::Instance()->PostTask(m_taskProxy);
	m_taskProxy->Control(false);
	
	return 0;
}
發佈了56 篇原創文章 · 獲贊 18 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章