C++中的类与多线程
标签(空格分隔): 学习笔记
背景:项目需求得把原来写的一个单线程版本改为多线程实现,已达到速度需求。原本的单线程版本已经封装好成类。
一、多线程的循环创建、申请、及使用
按照惯例,先贴代码:
//头文件
#include <process.h>
//创建以及初始化锁
HANDLE hMutex;
hMutex = CreateMutex(NULL, FALSE, NULL);
//上锁
WaitForSingleObject(hMutex, INFINITE);
//解锁
ReleaseMutex(hMutex);
//循环开辟线程
//通过读取计算机的最大可用线程来开辟线程
const int num_threads = 8;
HANDLE handle[num_threads];
for (int i = 0; i < num_threads; i++)
{
//HANDLE handle = INVALID_HANDLE_VALUE;
unsigned int id[num_threads] = { 0 };
handle[i] = (HANDLE)_beginthreadex(NULL, 0, singleChannelFunc, this, 0, &id[i]);
}
WaitForMultipleObjects(num_threads, handle, true, INFINITE);
for (int i = 0; i < num_threads; i++)
{
CloseHandle(handle[i]);
}
其中,开辟线程的数目可有自己的程序需求而定,当然如果你需要的线程越多越好,那么下面这个函数可以帮你获取到此台计算机当中最大可用线程,包含头文件”windows.h”
static int get_processor_number()
{
SYSTEM_INFO info;
GetSystemInfo(&info);
return (int)info.dwNumberOfProcessors;
}
二、类和多线程之间的调用关系
详细步骤:
1、在开辟线程之前先维护一个队列,该队列存放需要分发给各单个线程的数据信息。(针对我的项目来说,将图像块的起始点位置ij以及图像块的长宽hw存放在队列里面)更为具体的来说,单线程的程序中,分配好图像块之后调用的执行参数压到队列里面。
单线程程序
class A;
//分块
for(int i = 0;i < rows_num;i++)
{
for(int j = 0;j < cols_num ;j++)
{
i_idx = blk.col * i;
j_idx = blk.row * j;
A.run(i_idx,j_idx,blk.row.blk.col);
}
}
改写为相应的多线程部分
class Para
{
para1;
para2;
para3;
para4;
}
//维护队列
queue <class Para> queue_img_info;
//分块
for(int i = 0;i < rows_num;i++)
{
for(int j = 0;j < cols_num ;j++)
{
i_idx = blk.col * i;
j_idx = blk.row * j;
Para parameter;
parameter.para1 = i_idx;
parameter.para2 = j_idx;
parameter.para3 = blk.row;
parameter.para4 = blk.col;
queue_img_info.push(parameter);
}
}
2、写多线程调用的类内部接口方法和外部单线程工作的接口函数
由于语法的规定,单个线程的执行函数的输入参数必须是void*,则单线程的函数只需要做两件事情:将void*的输入强制类型转换为A*,然后调用A*类的内部多线程接口方法;
外部接口函数,只需要定义每个单个线程需要干什么事就行
unsigned int _stdcall singleChannelFunc(void * pm)
{
A *ptr_solver = static_cast<A*>(pm);
ptr_solver->singleChanFunInterface();
return 0;
}
A类内部的多线程接口函数,它需要规定线程锁定释放的顺序
void APSR_solver::singleChanFunInterface()
{
while (1)
{
//有线程进来,立马上锁
WaitForSingleObject(hMutex, INFINITE);
//如果队列为空,代表当前没有任务需要进行处理,立马开锁
if (queue_img_info.empty())
{
ReleaseMutex(hMutex);
break;
}
//单个线程获得队列信息
Para para = queue_img_info.front();
//将处理的队列中的第一块拿走
queue_img_info.pop();
//开锁
ReleaseMutex(hMutex);
//执行单线程任务(A)
run(para.para1,para.para2,para.para3,para.para4);
}
}
3、在类中的执行函数中开辟线程,其中每个线程都调用单线程函数
//开辟线程
const int num_threads = 8;
//定义线程句柄
HANDLE handle[num_threads];
for (int i = 0; i < num_threads; i++)
{
unsigned int id[num_threads] = { 0 };
//将每个线程都关联类外的单线程函数,冰纯如this指针
handle[i] = (HANDLE)_beginthreadex(NULL, 0, singleChannelFunc, this, 0, &id[i]);
}
//等待多线程执行任务
WaitForMultipleObjects(num_threads, handle, true, INFINITE);
//循环关闭句柄
for (int i = 0; i < num_threads; i++)
{
CloseHandle(handle[i]);
}
以上就是将一个封装好的类中的单线程方法改实现为多线程。