一、Windows创建线程

我们先来看一下创建windows线程的API

WINBASEAPI
_Ret_maybenull_
HANDLE
WINAPI
CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ SIZE_T dwStackSize,
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,
    _In_ DWORD dwCreationFlags,
    _Out_opt_ LPDWORD lpThreadId
    );

以下是形参的具体用途
lpThreadAttributes 线程安全有关,一般传入null
dwStackSize 分配的空间大小,0为自动分配
lpStartAddress 需要在线程中执行的函数
lpParameter 传入的参数
dwCreationFlags 控制线程的标准,0为一开始就执行,#define CREATE_SUSPENDED 0x00000004 为开始挂起
lpThreadId 线程的id

定义在window线程中执行的函数

DWORD WINAPI FuncThread(LPVOID lpParam)
{
	Sleep(1000);
	std::cout << "Hello World" << std::endl;
	return 0l;
}

创建windows线程,注意使用完毕后要CloseHandle。
windows的一些操作都要使用CloseHandle

	HANDLE h = CreateThread(nullptr, 0, FuncThread, nullptr, 0, nullptr);
	Sleep(2000);
	CloseHandle(h);

二、Windows互斥锁

WINBASEAPI
_Ret_maybenull_
HANDLE
WINAPI
CreateMutexW(
    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
    _In_ BOOL bInitialOwner,
    _In_opt_ LPCWSTR lpName
    );

lpMutexAttributes 线程安全有关,一般传入null
bInitialOwner 有没有该锁的控制权
lpName 锁的名称

WaitForSingleObject 是类似lock一样的上锁,后面的参数为等待的时间
ReleaseMutex(WindowMu) 是类似unlock的功能,释放这个锁

DWORD WINAPI Func01(LPVOID Params)
{
	WaitForSingleObject(WindowMu, INFINITE);
	std::cout << "Hello World" << std::endl;
	ReleaseMutex(WindowMu);
	return 0;
}

下面是使用案例

	WindowMu = CreateMutex(nullptr, false, L"TestLock");

	WaitForSingleObject(WindowMu, INFINITE);
	HANDLE h = CreateThread(nullptr, 0, Func01, nullptr, 0, nullptr);

	Sleep(5000);
	ReleaseMutex(WindowMu);

	Sleep(2000);

三、windows挂起和唤醒线程

和之前的std的线程一样都是使用一样的api

这个是挂起线程

	SuspendThread(h);

这个是唤醒线程

	ResumeThread(h);

四、简单架构Runnable

为了更方便的使用多线程,UE中有Runnable,仿造UE的实现,实现一个简易版本的
主要文件有三个Runnable、RunnableThread、Platform
在这里插入图片描述
Runnable.h

#pragma once

class RunnableThread;
class Runnable
{
public:
	Runnable();
	virtual bool Init();
	virtual int Run();
	virtual int Stop();
	virtual bool Exit();
protected:
	virtual int Run_Func() = 0;

	bool bStop = false;
	RunnableThread* Thread;
};

Runnable.cpp

#include "Runnable.h"
#include "Platform.h"

Runnable::Runnable()
{
	Thread = Platform::Create(this);
}

bool Runnable::Init()
{
	return true;
}

int Runnable::Run()
{
	for(;;)
	{
		while (!bStop)
		{
			Run_Func();
			Platform::Sleep(100);
		}
		Exit();
		break;
	}
	return 0;
}

int Runnable::Stop()
{
	if (!bStop) 
	{
		bStop = true;
	}
	return 0;
}

bool Runnable::Exit()
{
	return true;
}

RunnableThread.h

#pragma once
#include "Runnable.h"
class RunnableThread
{
public:
	RunnableThread();

	virtual bool Create(Runnable* Runnable) = 0;
};

RunnableThread.cpp

#include "RunnableThread.h"

RunnableThread::RunnableThread()
{
}

Platform.h

#pragma once

class Runnable;
class RunnableThread;

typedef unsigned long SLEEP_TIME;

class Platform
{
public:
	static RunnableThread* Create(Runnable* Runnable);
	static void Sleep(SLEEP_TIME SpTime);
};

Platform.cpp

class WindowsRunnableThread : public RunnableThread
{
protected:
	HANDLE ThreadHandle;
public:
	bool Create(Runnable* InRunnable) override
	{
		auto ThreadFunc = [](LPVOID Params) -> DWORD
			{
				Runnable* runnable = (Runnable*)Params;

				if (runnable)
				{
					DWORD ReturnValue = runnable->Run();

					return ReturnValue;
				}

				return 0;
			};
		ThreadHandle = CreateThread(nullptr, 0, ThreadFunc, InRunnable, 0, nullptr);
		return true;
	}

	~WindowsRunnableThread()
	{
		CloseHandle(ThreadHandle);
		delete ThreadHandle;
	}
};

class LinuxRunnableThread : public RunnableThread
{
	bool Create(Runnable* Runnable) override
	{
		return false;
	}
};

RunnableThread* Platform::Create(Runnable* Runnable)
{
	RunnableThread* Thread = nullptr;

	if (Runnable)
	{
		if (Runnable->Init())
		{
#if _WIN32
			Thread = new WindowsRunnableThread();
#elif __linux__
			Thread = new LinuxRunnableThread();
#endif
			if (Thread->Create(Runnable)) {
				return Thread;
			}
			else {
				delete Thread;
				return nullptr;
			}
		}
	}

	return Thread;
}

void Platform::Sleep(SLEEP_TIME SpTime)
{
#if _WIN32
	::Sleep(SpTime);
#elif __linux__
#endif
}

  • RunnableThread:对线程进行封装的接口,具体平台的线程需要继承此接口进行具体的线程创建。
  • Runnable:有关具体需要在线程中执行的函数的声明周期。
  • Platform:创建具体平台对应的线程,类似工厂。

五、线程命名修改

我们创建的子线程名称是系统自动生成的,如果我们需要自己修改创建的名称该如何处理?
一种老式的固定写法(调试器可见)

struct FThreadInfo
{
		DWORD dwType;
		LPCSTR szName;
		DWORD dwThreadID;
		DWORD dwFlags;
};

FThreadInfo ThreadInfo;
ThreadInfo.dwType = 0x1000;
ThreadInfo.szName = runnable->GetThread()->GetThreadName();
ThreadInfo.dwThreadID = GetCurrentThreadId();
ThreadInfo.dwFlags = 0;

__try
{
	RaiseException(0x406D1388, 0, sizeof(ThreadInfo) / sizeof(DWORD), (ULONG_PTR*)(&ThreadInfo));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐