windows多线程编程

当进程结束后所有线程都终止。多线程编程最大的问题在于共享数据的访问控制。
直接用Win32 API进行编程有很多优点:基于Win32的应用程序执行代码小,运行效率高。但是它要求程序员编写的代码较多,且需要管理所有系统提供给程序的资源。

▶ 创建线程

HANDLE CreateThread(      
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD     
SIZE_T dwStackSize,                                    // initial stack size     
LPTHREAD_START_ROUTINE lpStartAddress,    // thread function     
LPVOID lpParameter,                                    // thread argument     
DWORD dwCreationFlags,                            // creation option     
LPDWORD lpThreadId                                 // thread identifier   
);    
 线程函数原型:DWORD WINAPI Fun(LPVOID lpParamter);
 参数说明:
lpThreadAttributes :NULL使用默认安全性,不可以被子线程继承,否则需要定义一个结构体将它的bInheritHandle成员初始化为TRUE。
dwStackSize:设置初始栈的大小,以字节为单位,如果为0,那么默认将使用与调用该函数的线程相同的栈空间大小。任何情况下,Windows根据需要动态延长堆栈的大小。
lpStartAddress:指向线程函数的指针,形式:@函数名,函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (LPVOID lpParam) ,格式不正确将无法调用成功。但lpStartAddress要这样通过LPTHREAD_START_ROUTINE转换如:(LPTHREAD_START_ROUTINE)MyVoid。MyVoid声明为 void MyVoid();
lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。
dwCreationFlags:可取如下标志
1. CREATE_SUSPENDED(0x00000004):创建一个挂起的线程
2. 0:表示创建后立即激活
3. STACK_SIZE_PARAM_IS_A_RESERVATION(0x00010000):dwStackSize参数指定初始的保留堆栈的大小,否则,dwStackSize指定提交的大小。该标记值在Windows 2000/NT and Windows Me/98/95上不支持。
lpThreadId:保存新线程的id。
返回值:
如果CreateThread成功,传回一个handle,代表新线程。否则传回一个FALSE。如果失败,你可以调用GetLastError()获知原因。
必须指定的参数是lpStartAddress,其它的都可以用默认值0或NULL。

 恢复/挂起线程

DWORD WINAPI ResumeThread( __in HANDLE hThread);
调用该函数可以激活一个挂起的线程。
这个函数和SuspendThread相对应。创建线程是可以创建挂起的线程
(dwCreationFlags参数指定),挂起的线程直到调用ResumeThread才开始执行。

 设置线程优先级
BOOL SetThreadPriority(
  HANDLE hThread, // handle to the thread
  int nPriority     // thread priority level
);
 nPriority 优先级别参数 可设置为以下参数
THREAD_PRIORITY_ABOVE_NORMAL 为比一般优先级高一个等级
THREAD_PRIORITY_BELOW_NORMAL 比一般低一个等级
THREAD_PRIORITY_HIGHEST   比一般高2个等级
THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST    比一般低2个等级
THREAD_PRIORITY_NORMAL   一般等级
THREAD_PRIORITY_TIME_CRITICAL

 终止线程

 线程内终止
如果某线程调用了ExitThread函数就可以终止它自己。
VOID ExitThread(DWORD dwExitCode);
dwExitCode: 指定线程的推出码。
 线程外终止
BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode);
作用: 
在线程外终止一个线程,用于强制终止线程。 
参数说明: 
HANDLE htread:被终止的线程的句柄,为CWinThread指针。 
DWORD dwExitCode:退出码。

 关闭句柄

在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。
但是这个handle并不能完全代表这个线程,它仅仅是线程的一个“标识”,系统和用户可以利用它对相应的线程进行必要的操纵。如果在线程成功创建后,不再需要用到这个句柄,就可以在创建成功后,线程退出前直接CloseHandle掉,但这并不会影响到线程的运行。

不执行CloseHandle() 带来的后果:
若在线程执行完之后,没有通过CloseHandle()将引用计数减1,在进程执行期间,将会造成内核对象的泄露,相当与句柄泄露,但不同于内存泄露, 这势必会对系统的效率带来一定程度上的负面影响。但是,请记住,当进程结束退出后,系统仍然会自动帮你清理这些资源。但是在这里不推荐这种做法,毕竟不是 一个良好的编程习惯!
( 应用程序运行时,有可能泄露内核对象,但是当进程终止运行时,系统能确保所有内容均被正确地清除。另外,这个情况是用于所有对象,资源和内存块,也就是说,当进程终止时,系统将保证不会留下任何对象。)

▶ 判断程序运行状态
线程结束代码可以藉由调用GetExitCodeThread()而得知。
BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode);

 同步与互斥

Win32 API提供了一组能是线程阻塞自身执行的等待函数。这些等待函数在其参数中的一个或多个同步对象产生了信号,或者超过规定的等待时间才会返回。在等待未返回时,线程处于等待状态,此时线程只消耗很少的CPU。
最常用的等待函数是:
DWORD WINAPI WaitForSingleObject(
  __in HANDLE hHandle,
  __in DWORD dwMilliseconds
);
 参数:
hHandle: 对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
当等待仍在挂起状态时,句柄被关闭,那么函数行为是未定义的。该句柄必须具有 SYNCHRONIZE 访问权限。
dwMilliseconds: 定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle 标记的对象被触发,或者时间到了。如果dwMilliseconds 为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds 为INFINITE,对象被触发信号后,函数才会返回。

返回值:
WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。
  WAIT_OBJECT_ 0  0x00000000 :核心对象已被激活
  WAIT_TIMEOUT  0x00000102:等待超时
WAIT_FAILED    0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码

原文地址:https://www.cnblogs.com/shockerjue/p/2837654.html