多核CPU加速并行计算的快捷开发和应用

  不知有多久没来CSDN写文章了,今天终于勤快了一回,把最近一周的一点业余研究心得总结成这个文章。研究这个问题,是为了寻找在OpenCL之外,可以优化CPU执行效率的方法,优化对三维场景中大量物体实时计算的效率。比如拾取,变换,物理效果之类。之前实践了OpenCL和DirectCompute,但是只能在公司的高级电脑上,在很多只有集成显卡而且还跑着WinXP的电脑上是无缘这些了。而本文要介绍的这个方法实现起来比较简单,只要有多核CPU就能加速,对操作系统也几乎没要求,更不需要搞复杂的 CUDA, OpenCL,DirectCompute 之类,所以我这种又懒又穷的人就自己用了。

设计思想

  利用多核CPU同时执行多个线程,使每个线程运行在一个CPU核心上,让线程保持连续多次运行,实现了并行计算。整个功能只用到了 Windows API,实现代码极少,根据这种实现思路,只要在提供线程API的操作系统中都可以很容易的实现。对于N核CPU可以达到N倍的并行加速效果。当然,这个用法只限于使用线程函数,加速效果也不能和显卡相比。

实现方法

  功能的实现主要是两部分,线程池线程并行控制。线程池提高了线程连续运行和重复使用的效率,线程并行控制最终实现了并行加速。

  (1).线程池 (Thread Pool)

  线程池是用来维持线程生命周期,重复执行多次任务,减少操作系统维护时间的一种线程管理方法。一个线程在创建后,一旦运行结束,这个线程就不存在了,操作系统在创建线程和线程执行结束时都需要做很多底层操作。如果执行大量的异步任务,只是简单的给每次任务逐个创建线程,操作系统会浪费很多时间和资源,最终多个线程并行的时间很难比顺序执行更快。线程池使一个线程重复执行多次线程函数,而这个线程不会立刻结束,这样就保证了线程在运行多个任务时始终存在。

  最简单的线程池的实现如下:

//用户函数类型:
typedef void (*UserThreadProc)();
//创建一个执行队列(其实就是数组),把它作为参数传递给下面的内部线程函数,在线程中执行这个队列。
std::vector<UserThreadProc> tasklist;
//内部的线程函数,这个是线程直接运行的函数,在这个函数里调用队列中的函数。
DWORD __stdcall  _InternalThreadProc(LPVOID args)
{
    std::vector<UserThreadProc>* tasklist = (std::vector<UserThreadProc>*)args;
    for(std::vector::iterator i = tasklist->begin(); i!=tasklist->end(); i++)
    {
        (*i)();
    }
    tasklist->clear();
    return NULL;
};
//应用程序如下:
void MyTaskFunc()//实现一个线程函数作为任务。
{
    //Do some hard work.
};
void main()
{
    // 向队列中放入100个任务,这里只是简单的重复调用”MyTaskFunc()”。
    tasklist.resize(100, MyTaskFunc);
    // 使用Windows API创建一个线程,但是指定线程函数为"_InternalThreadProc",把执行队列"tasklist"作为参数传入。
    HANDLE thread = CreateThread(NULL, NULL, _InternalThreadProc, &tasklist, NULL, NULL);
    // 现在这个线程开始执行这100次任务了。
    WaitForSingleObject(thread, INFINITE);//等待完成即可。
};

  这个线程池只是个简单的例子,没有用户参数,也不能控制线程的运行,毫无实用意义,需要继续改进。改进后如下:

//定义一个有参数和返回值的用户函数类型
typedef __int64 (*UserThreadProc)(__int64 user_args);
//然后定义一个结构保存异步执行的信息。
struct AsyncState
{
    UserThreadProc func; //用户执行的函数。
    __int64 params; //用户函数的参数。通过保存地址可以转换成任意类型。
    __int64 result; //用户函数的返回值。通过保存地址可以转换成任意类型。
    bool is_finished; //指示是否执行完成。由底层来设置,调用者就别随意修改了。
};
//现在可以定义一个线程池对象:
class CThreadPool
{
private:
    bool                        m_enable;
    HANDLE                      m_thread;
    std::queue<AsyncState*>     m_tasklist;
public:
    CThreadPool();
    ~CThreadPool();
    void enqueue(AsyncState* user_call);
    size_t curr_pending_tasks();
};
//然后实现一个改进的线程函数,把线程池对象自身当做参数传入。
DWORD __stdcall _InternalThreadProc(LPVOID args)
{
    CThreadPool* tp = (CThreadPool*)args;
    while(tp->m_enable)
    {
        while(tp->m_tasklist.size())
        {
            AsyncState* as = tp->m_tasklist.front();
            as->result = as->func(as->params);
            as->is_finished = true;
            tp->m_tasklist.pop();
        }
        SuspendThread(tp->m_thread);
    }
};
//然后CThreadPool可以用以下的代码实现:
CThreadPool::CThreadPool()
{
    this->m_enable = true;
    this->m_thread = CreateThread(NULL,NULL,_InternalThreadProc,this,CREATE_SUSPENDED,NULL);
}
CThreadPool::~CThreadPool()
{
    this->m_enable=false;
    ResumeThread(this->m_thread);
    WaitForSingleObject(this->m_thread,INFINITE);
}
void CThreadPool::enqueue(AsyncState* user_call)
{
    user_call->is_finished=false;
    this->m_tasklist.push(user_ca
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值