http://www.cnblogs.com/uvsjoh/archive/2012/12/23/2822917.html
当进程结束后所有线程都终止。多线程编程最大的问题在于共享数据的访问控制。
直接用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得到错误代码