Thread
CreateEvent
创建线程:
- pThreadAttrivutes:指向SECURITY_ATTRIBUTES的指针,用于定义新线程的安全属性,一般设置成NULL;
- dwStackSize:分配以字节数表示的线程堆栈的大小,默认值是0;
- lpStartAddress:指向一个线程函数地址。每个线程都有自己的线程函数,线程函数是线程具体的执行代码;
- lpParameter:传递给线程函数的参数;
- dwCreationFlags:表示创建线程的运行状态,其中CREATE_SUSPEND表示挂起当前创建的线程,而0表示立即执行当前创建的进程;
- lpThreadID:返回新创建的线程的ID编号;
-
如果函数调用成功,则返回新线程的句柄。
//Definition HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadID ); //Example #include "windows.h" DWORD WINAPI ThreadFunc(LPVOID); int main(array<System::String^>^ args) { HANDLE hThread; DWORD threadId; hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, &threadId); // 创建线程 printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid Sleep(2000); if (hThread == NULL) { std::cerr << "CreateThread failed (error " << GetLastError() << ")" << std::endl; return 1; } WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); return 0; } DWORD WINAPI ThreadFunc(LPVOID p) { printf("我是子线程, pid = %d\n", GetCurrentThreadId()); //输出子线程pid return 0; }
WaitForSingleObject
调用WaitForSingleObject函数等待所创建线程的运行结束。
- hHandle:指定对象或时间的句柄;
-
dwMilliseconds:等待时间,以毫秒为单位,当超过等待时间时,此函数返回。如果参数设置为0,则该函数立即返回;如果设置成INFINITE,则该函数直到有信号才返回。
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
线程同步
一般情况下需要创建多个线程来提高程序的执行效率,但是多个线程同时运行的时候可能调用线程函数,在多个线程同时对一个内存地址进行写入操作,由于CPU时间调度的问题,写入的数据会被多次覆盖,所以要使线程同步。
线程和线程句柄
线程和线程句柄(Handle)不是一个东西,线程是在cpu上运行的,线程句柄是一个内核对象。我们可以通过句柄来操作线程,但是线程的生命周期和线程句柄的生命周期不一样的。线程的生命周期就是线程函数从开始执行到return,线程句柄的生命周期是从CreateThread返回到你CloseHandle()。所有的内核对象(包括线程Handle)都是系统资源,用了要还的,也就是说用完后一定要closehandle关闭之,如果不这么做,你系统的句柄资源很快就用光了。CloseHandel(ThreadHandle)只是关闭了一个线程句柄对象,表示我不再使用该句柄,即不对这个句柄对应的线程做任何干预了。并没有结束线程。
CloseHandle
理论上不能重复关闭句柄,在debug模式下会报错,但是在release模式下不会报错,关闭句柄不会把句柄设置为0。
MFC多线程函数,AfxBeginThread
UINT ThreadFunc(LPVOID lParam)
{
while (true) {
cout << "子线程" << endl;
Sleep(1000);
}
}
int main()
{
AfxBeginThread(ThreadFunc, NULL);
Sleep(10000);
return 0;
}
中止线程
- 线程函数返回(最好使用该方法)。
- 同一个进程或另一个进程中的线程调用TerminateThread函数(应避免使用该方法)。
- 通过调用ExitThread函数,线程将自行撤消(最好不使用该方法)。
- ExitProcess和TerminateProcess函数也可以用来终止线程的运行(应避免使用该方法)。
中止线程设计规范
始终都应该将线程设计成这样的形式,即当想要线程终止运行时,它们就能够返回。这是确保所有线程资源被正确地清除的唯一办法。如果线程能够返回,就可以确保下列事项的实现:
- 在线程函数中创建的所有C++对象均将通过它们的析构函数进行释放。
- 操作系统将正确地释放线程堆栈使用的内存。
- 系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
- 系统将递减线程内核对象的使用计数。