要在Windows上使用C++记录通过 CreateThread 创建的线程的创建和消失,包括处理线程异常退出的情况,你可以采取以下步骤:
- 创建线程时记录信息
- 在线程入口函数中记录开始和结束
- 使用
SetUnhandledExceptionFilter捕获未处理的异常
以下是一个示例,展示如何实现上述步骤:
示例代码
#include <windows.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <mutex>
std::mutex logMutex;
std::vector<HANDLE> threadHandles;
void Log(const std::string& message) {
std::lock_guard<std::mutex> lock(logMutex);
std::ofstream logFile("thread_log.txt", std::ios::app);
if (logFile.is_open()) {
logFile << message << std::endl;
}
}
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
int threadId = GetCurrentThreadId();
Log("Thread started: " + std::to_string(threadId));
__try {
// Simulate work
for (int i = 0; i < 10; ++i) {
Sleep(500);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Log("Thread exception caught: " + std::to_string(threadId));
}
Log("Thread ended: " + std::to_string(threadId));
return 0;
}
LONG WINAPI CustomUnhandledExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo) {
int threadId = GetCurrentThreadId();
Log("Unhandled exception in thread: " + std::to_string(threadId));
return EXCEPTION_EXECUTE_HANDLER;
}
int main() {
SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter);
const int numThreads = 5;
for (int i = 0; i < numThreads; ++i) {
DWORD threadId;
HANDLE threadHandle = CreateThread(
NULL,
0,
ThreadFunc,
NULL,
0,
&threadId
);
if (threadHandle != NULL) {
threadHandles.push_back(threadHandle);
Log("Thread created: " + std::to_string(threadId));
} else {
Log("Failed to create thread: " + std::to_string(i));
}
}
// Wait for all threads to finish
WaitForMultipleObjects(threadHandles.size(), threadHandles.data(), TRUE, INFINITE);
// Clean up handles
for (HANDLE handle : threadHandles) {
CloseHandle(handle);
}
Log("All threads have completed.");
return 0;
}解释
-
Log 函数:
- 使用互斥锁保护日志文件的写入,确保线程安全。
-
ThreadFunc 函数:
- 每个线程在启动时记录其 ID。
- 使用
__try和__except捕获异常并记录。
-
CustomUnhandledExceptionFilter 函数:
- 捕获未处理的异常并记录。通过
SetUnhandledExceptionFilter设置为全局异常处理函数。
- 捕获未处理的异常并记录。通过
-
main 函数:
- 创建多个线程,并记录每个线程的创建。
- 使用
WaitForMultipleObjects等待所有线程完成。 - 清理线程句柄。
这样做可以确保在 Windows 上使用 C++创建的线程,其创建和销毁过程都被记录下来,包括处理异常退出的情况。
在Windows平台上,__try 和 __except 是特定于Windows的结构化异常处理(Structured Exception Handling,SEH)机制,而 try 和 catch 是标准C++的异常处理机制。使用SEH和标准C++异常处理机制的原因和区别如下:
SEH (__try 和 __except)
- 系统级异常:SEH可以捕获系统级的异常,例如访问违规、除零错误、堆栈溢出等。这些异常通常不会被标准C++的
try和catch捕获到。 - 性能:SEH的异常处理机制是内嵌在操作系统内核中的,处理效率高,适用于捕获低级别的异常。
- 平台特定:SEH是Windows平台特有的,因此代码的可移植性较差。
标准C++异常处理 (try 和 catch)
- 用户级异常:标准C++的异常处理机制主要用于处理用户级异常(例如,逻辑错误、无效输入等),它不能捕获所有的系统级异常。
- 可移植性:C++的
try和catch是跨平台的,代码可移植性好。 - 类型安全:标准C++异常处理是类型安全的,可以捕获特定类型的异常。
为什么使用__try 和 __except 而不是 try 和 catch?
在某些情况下,我们需要捕获系统级的异常,这些异常可能会导致程序崩溃。这时,使用 __try 和 __except 更合适。例如,当你创建多个线程并希望记录线程异常退出的情况时,如果这些异常是由于访问无效内存或除零等系统级错误引起的,标准的 try 和 catch 是无法捕获的。因此,使用 __try 和 __except 更为合适。