KMThreadPool: 4 – Thread Pool Step 2: SettingUp the Threads

构建高效线程池管理器
本文详细介绍了如何创建一个线程池管理器,包括线程的创建、任务的分配和执行,以及线程的结束流程。通过封装KMTask类来管理任务数据,确保资源的有效利用和线程的安全运行。

4 – Thread Pool Step 2: SettingUp the Threads

KMTask

Lets go back to the heart of thethread pool (or to those in denial, the liver): The tasks. To keep everythingmanaged and such, we’ve encapsulated the KMTaskFunc and IKMTaskData* inside the KMTask class, just so we can keep things managed(and modular; so you can add new functionality like dependencies or referencesor contexts or whatever you’d like in the future).

class KMTask
{
private:
         KMTaskFunc         m_task;
         IKMTaskData*         m_data;
public:
         KMTask(KMTaskFunc task, IKMTaskData* data)
         {
                  m_task = task;
                  m_data = data;
         }
         ~KMTask()
         {
                  if(m_data!=NULL)
                       delete m_data;
                  m_data = NULL;
                  m_task = NULL;
         }
         KMTaskFunc         GetTask()         { return m_task; }
         IKMTaskData*         GetData()         { return m_data; }
protected:
};

Not so bad. Just manages the datafor us. This way we don’t really have to explicitly delete the IKMTaskData* inside our task.

KMThread

Here is the logic behind ourthreads: 1. Create the thread when the threadpool starts up, 2. Idle until wefind a task in the thread pool, 3. Run the task, 4. When we finish, clean upthe memory, 5. Goto 2 (6. Beat up the guy who wrote this tutorial for using agoto).

Here is a quick rundown of themembers in the threads:

KMThreadpool*          m_pthreadpool;
 
HANDLE                 m_hthread;
KMLock                 m_lock;
KMTask*                m_ptask;
 
bool                   m_brunning;
bool                   m_bpaused;
unsigned int           m_uithreadID;
DWORD                  m_dwexit;

m_pthreadpool is apointer to the actual thread pool class, and you’ll see why we need that injust a minute.
m_hthread is a handle (a kind ofsmart pointer) to the thread in the Windows API.
m_lock is the oneone lock we need to protect executing our task with.
m_ptask is thetask we get from the thread pool.
m_brunning is a flagthat’s set to true once the thread initializes successfully, and false if itfails or gets shut down.
m_bpaused is… uhh…legacy code! (meaning: code I forgot to delete, but isn’t breaking anything)
m_uithreadID is anID assigned from the Windows API.
m_dwexit is theexit code returned once the thread shuts down for any reason.

Now there are a few accessorfunctions and such, but we want to focus on 4 main functions:

public:
         void Begin();
         void End();
         DWORD ThreadProc();
protected:
         static unsigned __stdcall cThreadProc(LPVOID _pThis)
         {
                  return ((KMThread*)_pThis)->ThreadProc();
         }

Now, you see cThreadProc(). This function is called by the WindowsAPI when you create the thread. The API will be calling this function, and thisfunction calls ThreadProc(), and ThreadProc() runs our task. Indirection out thewazzoo, baby!

Next we have Begin(). Nothing too special here for anyone whohas ever created threads before. We grab the instance of our thread pool(because it’s a singleton), then we create our thread using _beginthreadex(), and if m_hthread isn’t NULL, then it was a success! Once again, verysimple.

void KMThread::Begin()
{
         // Set our thread pool
         m_pthreadpool = KMThreadpool::getInstance();
#if defined( _WIN32 )
         // Start the thread.
         m_hthread = (HANDLE)_beginthreadex( NULL,
                  0,
                  &cThreadProc,
                  (void*)this,
                  0,
                  &m_uithreadID );
         m_brunning = true;
         if( m_hthread == NULL )
         {
                  // You can add extra error-handling here.
                  m_brunning = false;
         }
#endif /* defined( _WIN32 ) */
}

And for every Begin(), there must be an End().

void KMThread::End()
{
#if defined( _WIN32 )
         if( m_hthread != NULL )
         {
                  m_brunning = false;
                  WaitForSingleObject( m_hthread, INFINITE );
                  DWORD ExitCode;
                  GetExitCodeThread( m_hthread, &ExitCode );
                  m_dwexit = ExitCode;
                  CloseHandle( m_hthread );
                  m_hthread = NULL;
         }
#endif /* defined( _WIN32 ) */
}

People familiar with somemultithreading experience may throw up a red flag and say “Hey! Why aren’t youusing _endthreadex()? Duh!” Well, Mr. NonBeliever, _endthreadex() in the Win32 API does not closethe handle. This explicit way of closing the thread allows me to free up allnecessary memory and allows me to get the exit codes and such. And for newbiesto threading, that WaitForSingleObject() function is also part of the Win32 API.It waits for the handle to the thread to finish its current cycle (for an INFINITE amount of time), and stops it fromcontinuing so we can manipulate the handle (in this case, closing the handle).

The last major function in thisclass is the full-on assembily of the circulatory system of the thread pool:The ThreadProc() function. This function is in charge of processing the actual task andgrabbing a new task once we finish. However, it’s not as simple as just run thetask and get a new one from the queue. We have to be safe and slick when we dothis. Here’s a look at the code:

DWORD KMThread::ThreadProc()
{
         m_ptask = NULL;
         // The main thread-loop. As long as this loop
         // is running, the thread stays alive.
         while(m_brunning)
         {
                  Sleep(1);
                  // The thread pauses when it finishes a task.
                  // Adding a task resumes it.
                  if(m_ptask != NULL)
                  {
                       m_lock.Lock();
                       {
                                KMTaskFunc task = m_ptask->GetTask();
                                IKMTaskData* data = m_ptask->GetData();
                                // Run the actual task
                                if(task != NULL && data != NULL)
                                {
                                     task(data);
                                }
                                // Task is complete.
                                delete m_ptask;
                                m_ptask = NULL;
                       }
                       m_lock.Unlock();
                  }
                  // If we're finished with our task, grab a new one.
                  if(m_ptask == NULL && m_pthreadpool->IsProcessing() == true)
                  {
                       m_ptask = m_pthreadpool->m_qtaskList.pop();
                  }
         }
         return 0;
}

The thread is almost set up asits own program, with the main thread loop in there. It’s set up so as long asthe thread is running (set by either begin(), end() or by the thread pool), it will do thework inside.
First thing we do inside this loop is Sleep(1). When I originally wrote the thread pool,I wasn’t calling Sleep(), and all my threads became processor hogs. If you downloaded the code orare writing it yourself, go ahead and comment out the Sleep() call and watch your computer burn!

Next, we check to see if the m_ptask is NULL.

  • If it isn’t, then we go ahead and process it. We lock around the tasks to protect the data from getting possibly modified by another thread, and after we call the task (like you would with any normal function) we go and clean up the data.
  • If it is, check the thread pool and get the next task in the queue.

And that’s our threads! Nifty!Now on to the main brain of the outfit… The interface for all thismultithreaded goodness…

 

转自:http://keithmaggio.wordpress.com/code/c-win32-thread-pool-manager/4-step2/

MATLAB主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性内容概要:本文主要介绍了一种在MATLAB环境下实现的主动噪声和振动控制算法,该算法针对较大的次级路径变化具有较强的鲁棒性。文中详细阐述了算法的设计原理与实现方法,重点解决了传统控制系统中因次级路径动态变化导致性能下降的问题。通过引入自适应机制和鲁棒控制策略,提升了系统在复杂环境下的稳定性和控制精度,适用于需要高精度噪声与振动抑制的实际工程场景。此外,文档还列举了多个MATLAB仿真实例及相关科研技术服务内容,涵盖信号处理、智能优化、机器学习等多个交叉领域。; 适合人群:具备一定MATLAB编程基础和控制系统理论知识的科研人员及工程技术人员,尤其适合从事噪声与振动控制、信号处理、自动化等相关领域的研究生和工程师。; 使用场景及目标:①应用于汽车、航空航天、精密仪器等对噪声和振动敏感的工业领域;②用于提升现有主动控制系统对参数变化的适应能力;③为相关科研项目提供算法验证与仿真平台支持; 阅读建议:建议读者结合提供的MATLAB代码进行仿真实验,深入理解算法在不同次级路径条件下的响应特性,并可通过调整控制参数进一步探究其鲁棒性边界。同时可参考文档中列出的相关技术案例拓展应用场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值