mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-08-30 04:15:10 +00:00
connection between 2 systems and bug fixes (#14)
This commit is contained in:
@@ -11,8 +11,8 @@
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef THREAD_POOL_H
|
||||
#define THREAD_POOL_H
|
||||
#ifndef SCHEDULER_H
|
||||
#define SCHEDULER_H
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@@ -27,33 +27,38 @@
|
||||
#include "../flags.h"
|
||||
|
||||
/**
|
||||
* @brief Job scheduler that uses a dynamic threadpool to schedule the task.
|
||||
* @brief Schedule flags to influence the scheduling.
|
||||
*/
|
||||
enum class EScheduleFlags
|
||||
{
|
||||
normal = 0x0, ///< If thread level threshold has been reached, queue the call at the end of the queue.
|
||||
priority = 0x1, ///< If thread level threshold has been reached, insert the call at the begin of the queue.
|
||||
no_queue = 0x2, ///< If thread level threshold has been reached, fail the schedule call.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Task scheduler that uses a dynamic threadpool to schedule the task.
|
||||
* @tparam TThread Type of thread class to use for scheduling; must be derived from std::thread.
|
||||
* @tparam nMinIdle The amount of idle threads that should stay present if there is nothing to process at the moment.
|
||||
* @tparam nMaxBusy The maximum amount of threads that is used for processing.
|
||||
*/
|
||||
template <class TThread = std::thread, size_t nMinIdle = 4, size_t nMaxBusy = 32>
|
||||
class CTaskScheduler
|
||||
{
|
||||
public:
|
||||
// The thread class must be derived from std::thread.
|
||||
static_assert(std::is_base_of_v<std::thread, TThread>);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] nMinIdle The amount of idle threads that should stay present if there is nothing to process at the moment.
|
||||
* @param[in] nMaxBusy The maximum amount of threads that is used for processing.
|
||||
*/
|
||||
CTaskScheduler(size_t nMinIdle = 4, size_t nMaxBusy = 32);
|
||||
CTaskScheduler();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CTaskScheduler();
|
||||
|
||||
/**
|
||||
* @brief Schedule flags to influence the scheduling.
|
||||
*/
|
||||
enum class EScheduleFlags
|
||||
{
|
||||
normal = 0x0, ///< If thread level threshold has been reached, queue the call at the end of the queue.
|
||||
priority = 0x1, ///< If thread level threshold has been reached, insert the call at the begin of the queue.
|
||||
no_queue = 0x2, ///< If thread level threshold has been reached, fail the schedule call.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Schedule the asynchronous execution of the task.
|
||||
* @details If an idle thread is available, the thread will execute the task. If no thread is available and the maximum thread
|
||||
@@ -125,7 +130,7 @@ private:
|
||||
*/
|
||||
void ThreadFunc();
|
||||
|
||||
std::thread m_thread; ///< The thread that executes the tasks.
|
||||
TThread m_thread; ///< The thread that executes the tasks.
|
||||
std::atomic_bool m_bShutdown = false; ///< Set when the thread should terminate.
|
||||
std::atomic_bool m_bStarted = false; ///< Set when the thread has started.
|
||||
std::function<void()> m_fnTask; ///< The task to execute (will be updated with new tasks before execution).
|
||||
@@ -143,15 +148,18 @@ private:
|
||||
* @param[in] itThread The thread to use for the execution.
|
||||
* @param[in] fnTask The task to execute.
|
||||
*/
|
||||
void Execute(std::list<std::shared_ptr<CThread>>::iterator itThread, std::function<void()> fnTask);
|
||||
void Execute(typename std::list<std::shared_ptr<CThread>>::iterator itThread, std::function<void()> fnTask);
|
||||
|
||||
size_t m_nMinIdle = 4; ///< The minimal required amount of idle threads
|
||||
size_t m_nMaxBusy = 32; ///< The maximum allowed amount of busy threads
|
||||
size_t m_nMaxThreads = 0; ///< The maximum amount threads at the same time.
|
||||
mutable std::mutex m_mtxQueueAccess; ///< Sync access to queue, list and double-ended-queue.
|
||||
std::queue<std::list<std::shared_ptr<CThread>>::iterator> m_queueIdleThreads; ///< Idle thread queue.
|
||||
std::list<std::shared_ptr<CThread>> m_lstThreads; ///< List with all threads.
|
||||
std::queue<typename std::list<std::shared_ptr<CThread>>::iterator> m_queueIdleThreads; ///< Idle thread queue.
|
||||
std::list<typename std::shared_ptr<CThread>> m_lstThreads; ///< List with all threads.
|
||||
std::deque<std::function<void()>> m_dequeTasks; ///< Double ended task queue.
|
||||
};
|
||||
|
||||
#endif // !defined THREAD_POOL_H
|
||||
// Include the implementation
|
||||
#include "scheduler.inl"
|
||||
|
||||
#endif // !defined SCHEDULER_H
|
||||
@@ -11,10 +11,17 @@
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SCHEDULER_H
|
||||
#include "scheduler.h"
|
||||
#endif
|
||||
|
||||
#ifndef SCHEDULER_INL
|
||||
#define SCHEDULER_INL
|
||||
|
||||
#include <cassert>
|
||||
|
||||
CTaskScheduler::CTaskScheduler(size_t nMinIdle /*= 4*/, size_t nMaxBusy /*= 32*/) :
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CTaskScheduler() :
|
||||
m_nMinIdle(nMinIdle), m_nMaxBusy(nMaxBusy)
|
||||
{
|
||||
// Check min/max values
|
||||
@@ -30,17 +37,20 @@ CTaskScheduler::CTaskScheduler(size_t nMinIdle /*= 4*/, size_t nMaxBusy /*= 32*/
|
||||
m_nMaxThreads = m_lstThreads.size();
|
||||
}
|
||||
|
||||
CTaskScheduler::~CTaskScheduler()
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::~CTaskScheduler()
|
||||
{
|
||||
WaitForExecution();
|
||||
}
|
||||
|
||||
bool CTaskScheduler::Schedule(std::function<void()> fnTask, hlpr::flags<EScheduleFlags> flags /*= 0*/)
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline bool CTaskScheduler<TThread, nMinIdle, nMaxBusy>::Schedule(std::function<void()> fnTask,
|
||||
hlpr::flags<EScheduleFlags> flags /*= 0*/)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
|
||||
|
||||
// Get a thread - either from the idle queue or new.
|
||||
std::list<std::shared_ptr<CThread>>::iterator itThread = m_lstThreads.end();
|
||||
typename std::list<std::shared_ptr<CThread>>::iterator itThread = m_lstThreads.end();
|
||||
if (m_queueIdleThreads.empty())
|
||||
{
|
||||
// No thread is available. Allowed to make one?
|
||||
@@ -77,7 +87,8 @@ bool CTaskScheduler::Schedule(std::function<void()> fnTask, hlpr::flags<ESchedul
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTaskScheduler::WaitForExecution()
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::WaitForExecution()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
|
||||
|
||||
@@ -111,31 +122,37 @@ void CTaskScheduler::WaitForExecution()
|
||||
m_nMinIdle = nMinIdleTemp;
|
||||
}
|
||||
|
||||
size_t CTaskScheduler::GetThreadCount() const
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetThreadCount() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
|
||||
return m_lstThreads.size();
|
||||
}
|
||||
|
||||
size_t CTaskScheduler::GetMaxThreadCount() const
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetMaxThreadCount() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
|
||||
return m_nMaxThreads;
|
||||
}
|
||||
|
||||
size_t CTaskScheduler::GetBusyThreadCount() const
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetBusyThreadCount() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
|
||||
return m_lstThreads.size() - m_queueIdleThreads.size();
|
||||
}
|
||||
|
||||
size_t CTaskScheduler::GetIdleThreadCount() const
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline size_t CTaskScheduler<TThread, nMinIdle, nMaxBusy>::GetIdleThreadCount() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mtxQueueAccess);
|
||||
return m_queueIdleThreads.size();
|
||||
}
|
||||
|
||||
void CTaskScheduler::Execute(std::list<std::shared_ptr<CThread>>::iterator itThread, std::function<void()> fnTask)
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::Execute(typename std::list<std::shared_ptr<CThread>>::iterator itThread,
|
||||
std::function<void()> fnTask)
|
||||
{
|
||||
std::shared_ptr<CThread>& rptrThread = *itThread;
|
||||
|
||||
@@ -176,16 +193,18 @@ void CTaskScheduler::Execute(std::list<std::shared_ptr<CThread>>::iterator itThr
|
||||
});
|
||||
}
|
||||
|
||||
CTaskScheduler::CThread::CThread()
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::CThread()
|
||||
{
|
||||
// Wait for the start
|
||||
std::unique_lock<std::mutex> lockStart(m_mtxSyncStart);
|
||||
m_thread = std::thread(&CThread::ThreadFunc, this);
|
||||
m_thread = TThread(&CThread::ThreadFunc, this);
|
||||
while (!m_bStarted)
|
||||
m_cvStarted.wait_for(lockStart, std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
CTaskScheduler::CThread::~CThread()
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::~CThread()
|
||||
{
|
||||
// Lock to prevent execution still to take place. Then shutdown.
|
||||
std::unique_lock<std::mutex> lock(m_mtxSyncExecute);
|
||||
@@ -196,7 +215,8 @@ CTaskScheduler::CThread::~CThread()
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void CTaskScheduler::CThread::Execute(std::function<void()> fnTask)
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::Execute(std::function<void()> fnTask)
|
||||
{
|
||||
// Assign the task and notify for execution.
|
||||
std::unique_lock<std::mutex> lock(m_mtxSyncExecute);
|
||||
@@ -205,7 +225,8 @@ void CTaskScheduler::CThread::Execute(std::function<void()> fnTask)
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
void CTaskScheduler::CThread::ThreadFunc()
|
||||
template <class TThread, size_t nMinIdle, size_t nMaxBusy>
|
||||
inline void CTaskScheduler<TThread, nMinIdle, nMaxBusy>::CThread::ThreadFunc()
|
||||
{
|
||||
// Thread has started (needed, since the condition variable doesn't keep its state).
|
||||
m_bStarted = true;
|
||||
@@ -232,3 +253,5 @@ void CTaskScheduler::CThread::ThreadFunc()
|
||||
m_fnTask = {};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined SCHEDULER_INL
|
||||
Reference in New Issue
Block a user