⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.cpp

📁 3D游戏开发需要用到BSP树来经行场景渲染的管理。本代码包含完整的BSP及文件生成实现
💻 CPP
字号:
/*
    Copyright (C) 2008 Rouslan Dimitrov

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "thread.h"
#include "log.h"

void DoWork(CThreadPool *pool);
DWORD WINAPI ThreadScheduler(LPVOID lpThreadPool);

// Unfortunately __forceinline doesn't inline this function
__declspec(naked) int __fastcall AtomicXAdd(int *, int) {
	__asm {
		lock xadd	[ecx], edx
		mov			eax, edx
		ret
	}
}

// This is serializing
__declspec(naked) int __fastcall GetCurrentProcessorNumberWinAll(void) {
    __asm {
	//	push	ebx
		mov		eax, 1
		cpuid
		shr		ebx, 24
		mov		eax, ebx	// initial APIC ID
	//	pop		ebx
		ret		0
	}
}

void CThreadPool::Init(bool useCaller) {
	DWORD		dwProcAffinityMask, dwSysAffinityMask;
	HANDLE		hCurProc = GetCurrentProcess();

	nThreads = 0;

	GetProcessAffinityMask(hCurProc, &dwProcAffinityMask, &dwSysAffinityMask);

	for(int cpu=0, first=1; cpu<MAX_THREADS; cpu++) {
		if(!(dwProcAffinityMask & (1<<cpu)))
			continue; // CPU isn't available

		if(useCaller && first) {
			// Leave the first available CPU for the calling thread
			first--;
			continue;
		}

		hThreads[nThreads] = CreateThread(0, 0, ThreadScheduler, this, 0, 0);

		if(!hThreads[nThreads]) {
			g_CLog.Log(LOG_SYSTEM, "Couldn't create a thread for cpu %d. Retrying...", cpu);
			Sleep(10);
			hThreads[nThreads] = CreateThread(0, 0, ThreadScheduler, this, 0, 0);
			if(!hThreads[nThreads])
				break;
		}

		hThreadsDone[nThreads] = CreateEvent(0, false, false, 0); // Auto reset event

		SetThreadIdealProcessor(hThreads[nThreads], cpu);
		nThreads++;
	}

	hMoreWork = CreateEvent(0, true, false, 0);

	useCallingThread = useCaller;
	bRunning = true;

	g_CLog.Log(LOG_SYSTEM, "Thread pool running %d threads.", nThreads + (int)useCaller);

	WaitThreads();
}

void CThreadPool::RunOn(WORKFUNC f, void* a, int s, int e) {
	function = f;
	argument = a;
	curIndex = s;
	endIndex = e;

	// TODO: MSDN says PulseEvent is unreliable, perhaps we need a loop with SetEvent?
	PulseEvent(hMoreWork);

	if(useCallingThread) {
		// HANDLE hCurThread = GetCurrentThread();
		// SetThreadIdealProcessor(hCurThread, 0);

		DoWork(this);

		// SetThreadIdealProcessor(hCurThread, MAXIMUM_PROCESSORS);
	}
}

void CThreadPool::ShutDown() {
	bRunning = false;

	SetEvent(hMoreWork);
	
	WaitThreadsToExit();

	for(int i=0; i<nThreads; i++)
		CloseHandle(hThreads[i]);
}

void DoWork(CThreadPool *pool) {
	int i;
	while(i = AtomicXAdd(&pool->curIndex, 1), i < pool->endIndex) {
		pool->function(i, pool->argument);
	}
}

void SignalAndWait(HANDLE& signal, HANDLE wait) {
	if(SignalObjectAndWait(signal, wait, INFINITE, false) == WAIT_FAILED) {
		// It is not clear from the spec whether the signaling or the waiting failed, so we exit the thread
		// Close the thread and change its event to remain always signaled
		CloseHandle(signal);
		signal = CreateEvent(0, true, true, 0);
		g_CLog.Log(LOG_SYSTEM, "Threading error. Killing 1 thread.");
		ExitThread(E_FAIL);
	}
}

DWORD WINAPI ThreadScheduler(LPVOID lpThreadPool) {
	CThreadPool*	pool = (CThreadPool*)lpThreadPool;
	static int		nThreads = 0;
	int				threadID = AtomicXAdd(&nThreads, 1);

	SignalAndWait(pool->hThreadsDone[threadID], pool->hMoreWork);

	while(pool->bRunning) {
		DoWork(pool);

		SignalAndWait(pool->hThreadsDone[threadID], pool->hMoreWork);
	}

	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -