受欢迎的博客标签

多核CPU并行编程:.Visual Studio c++ 多核并行运算编程实现之三:手工多核运行代码(通过Windows多线程库CreateThread实现)

Published

OS:Windows

一、基础知识

1.Window  可以选择的线程库有3种

AfxBeginThread是MFC的全局函数,是对CreateThread的封装。  

CreateThread是Win32 API函数,AfxBeginThread最终要调到CreateThread。

而_beginthread是C的运行库函数。

2.CreateThread

当使用CreateProcess调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:

(1)在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回

(2)把线程退出码置为STILL_ACTIVE,把线程挂起计数置1

(3)分配context结构

(4)分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD

(5)lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数

(6)把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数

 

 c++手工多核运行代码

首先把数组分成N段,然后创建N个线程,每个线程独自计算1段数据

MYDATA:

struct MYDATA {
	int begin, end;
	int* A, * B, * C;
	int P, N;
};

 

单独的运算线程

DWORD ThreadProc(LPVOID IpParam) {

	MYDATA* pmd = (MYDATA*)IpParam;
	int* A = pmd->A, * B = pmd->B, * C = pmd->C;
	int begin = pmd->begin, end = pmd->end, P = pmd->P, N = pmd->N;


	TRACE("执行时间total = %d ms, I am Thread %d\n", begin, end);

	CString	sTip;



	while (1)
	{

	}

	return 0;
}

 

把static MYDATA mydt[m]拆分成M段,然后调用M个线程进行计算

//multi thread test

	SYSTEM_INFO info;
	GetSystemInfo(&info);

	//线程数量
	const int NTHREADS = 1;
	HANDLE hThread[NTHREADS];


	//传入线程的参数,存放每个线程的分段起、止index
	static MYDATA thread_args[NTHREADS];

	//将长度为nSize的列表进行分段, temp就是平均到每个线程的计算元素
	int temp = (nSize) / NTHREADS;

	//计算每个线程要处理的起、止位置,存入mydt[]
	for (int i = 0; i < NTHREADS; ++i) {
		thread_args[i].begin = i * temp, thread_args[i].end = i * temp + temp;

		if (i == NTHREADS - 1) // 最后一个线程计算剩余的
			thread_args[i].end = nSize;

		//创建线程开始计算
		hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, &thread_args[i], 0, NULL);
	}
	//等待所有线程结束
	WaitForMultipleObjects(NTHREADS, hThread, TRUE, INFINITE);

 

SetThreadAffinityMask windows下线程指定CPU核心

实用的函数来获取当前CPU的核心数量

OS:Windows 10

CPU:Intel Core i5-10400

 

SYSTEM_INFO info;
GetSystemInfo(&info);
printf("Number of processors: %d.\n", info.dwNumberOfProcessors);

output

 

&info	0x002adc70 {dwOemId=0 wProcessorArchitecture=0 wReserved=0 ...}	_SYSTEM_INFO *
		dwOemId	0	unsigned long
		wProcessorArchitecture	0	unsigned short
		wReserved	0	unsigned short
		dwPageSize	4096	unsigned long
		lpMinimumApplicationAddress	0x00010000	void *
		lpMaximumApplicationAddress	0x7ffeffff	void *
		dwActiveProcessorMask	4095	unsigned long
		dwNumberOfProcessors	12	unsigned long
		dwProcessorType	586	unsigned long
		dwAllocationGranularity	65536	unsigned long
		wProcessorLevel	6	unsigned short
		wProcessorRevision	42243	unsigned short
		

子线程如何访问主线程的全局变量

 

主进程的全局变量对它的所有子线程都是有效的

1.创建子线程时,将主线程指针作为参数.
2.在子线程函数中,通过AfxGetApp()获得主线程指针.

一、主进程的全局变量对它的所有子线程都是有效的 
二、你可通过__beginthread(FuncName,0,pData) 传递给子线程你要访问的变量
其中 FuncName 为子线程函数的名称,pData为一个你要指向的传递的变量的指针

要子线程能看到主线程的全局变量的声明就可以了。
如不在同一文件,可在子线程的.cpp 文件里声明 
extern int g_var;

如果在同一个主线程里创多个子线程,恐怕不宜直接调用吧?

 

1.结构struct 包含class传递参数到子线程

struct threadInfo

{

    CDC * dc;        //画布

    int  nOffset;    //偏移量

    COLORREF clrRGB; //颜色

};

see:https://blog.csdn.net/cbNotes/article/details/8277180

2.CreateThread(...)传入多个参数

传递class作为参数到子线程

例子:
class    CThreadParam 
{ 
public: 
                     IVMManager    *m_pVMManager1; 
                     CString    m_strExtNum; 
                     //要多少参数就有多少参数 
}; 
CThreadParam    *pParam    =    new    CThreadParam; 
pParam-> m_pVMManager1=...; 
... 
DWORD    dwThreadId; 
CreateThread(    NULL,0,ThreadFunc,pParam,0,&dwThreadId); 

DWORD    WINAPI    CConnectDlg::ThreadFunc(    LPVOID    lpParam    ) 
{ 
//运行线程 
//强制指针类型转换 
(CThreadParam*)pMyParam    =    (CThreadParam*)lpParam; 
// 
//pMyParam-> m_pVMManager1 
//pMyParam-> m_strExtNum 
}