Windows线程
线程基础
- 
Windows线程是可以执行的代码的实例。 系统是以线程为单位调度程序,一个程序中可以有多个线程,实现多任务的处理。主线程只能有一个。 
- 
Windows线程的特点 - 线程都具有1个ID
- 每个线程都具有自己的内存栈,其余的共享。
- 同一进程中的线程使用同一个地址空间。(除了栈空间)
 
- 
线程的调度 操作系统将CPU的执行时间划分为时间片,依次根据时间片执行不同的线程。 线程轮询: 线程A -> 线程B ->线程A .... 
创建线程
- 
创建线程 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes , // 安全属性,已废弃, NULL SIZE_T dwStackSize, // 线程栈的大小 按1M对齐,最少1M LPTHREAD_START_ROUTINE lpStartAddress, // 线程处理函数的函数地址,自己定义由系统调用 LPVOID lpParameter, // 传递给线程处理函数的参数 DWORD dwCreationFlags, // 线程的创建方式(立即执行&挂起方式) // 0 -> 立即启动 // CREATE_SUSPENDED -> 挂起 LPDWORD lpThreadId // 创建成功,返回线程的ID ); // 创建成功,返回线程句柄 ( 线程句柄和线程ID都可以代表线程 )
- 
定义线程处理函数 DWORD WINAPI ThreadProc( LPVOID lpParameter // 创建线程时,传递给线程的参数 );
Demo
#include <windows.h>
#include <stdio.h>
DWORD CALLBACK TestProc(LPVOID pParam){
   char * pszText = (char *) pParam;
   printf("%s",pszText);
}
int main(){
    DWORD nID = 0;
    char * pszText = "******";
    HANDLE hThread = CreateThread(NULL,0,TestProc,pszText,0,&nID);
    getchar();
    return 0;
}
子线程正常执行->要保证主线程不结束
销毁线程
- 
挂起 DWORD SuspendThread( HANDLE hThread // 线程句柄 );
- 
唤醒 DWORD ResumeThread( HANDLE hThread // 线程句柄 );
- 
结束指定线程 BOOL TerminateThread( HANDLE hThread, // 线程句柄 DWORD dwExitCode // 退出码,一般没用 );
- 
结束函数所在的线程 VOID ExitThread( DWORD dwExitCode // 退出码,没有实际意义 ); // 自杀 -> 只能干掉调用的线程
线程相关操作
- 
获取当前线程ID GetCurrentThreadId();
- 
获取当前线程的句柄 GetCurrentThread();
- 
等候单个句柄有信号 VOID WaitForSingleObject( HANDLE handle , // 句柄BUFF的地址 DWORD dwMilliseconds // 最长等候时间 ms // INFINITE 一直等待 ); // 有信号时会立即返回 // 没有信号会阻塞线程句柄是可等候句柄: 有信号和无信号状态 
- 
同时等候多个句柄有信号 DWORD WaitForMultipleObject( DWORD nCount, // 句柄数量 CONST HANDLE *lpHandles, // 句柄BUFF的地址 BOOL bWaitAll, // 等候方式 // TRUE : 所有句柄都有信号才会返回 // FALSE: 只要有一个有信号就返回 DWORD dwMilliseconds // 等候时间 INFINITE );可等候句柄 
- 
线程信号 - 当线程处于执行状态时,线程无信号
- 当线程结束那刻,线程有信号
 
线程同步
原子锁
- 
当多个线程对同一个数据进行原子操作,会产生结果丢失,比如算术运算 
- 
使用原子锁函数 InterlockedIncrement // ++ 操作符 InterlockedDecrement // -- InterlockedCompareExchange // 三目运算符 InterlockedExchange // = 赋值原子锁的实现,直接对数据所在的内存操作,并且任何一个瞬间只能有一个线程访问。 
- 
只能对运算符加锁,效率高,但是麻烦 
互斥锁
- 
相关问题 多线程下代码或者资源的共享使用 
- 
互斥的使用 - 
创建互斥 HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全数据(NULL) BOOL bInitialOwner, // 初始的拥有者 TRUE/FALSE // TRUE: 哪个线程创建哪个线程拥有 // FALSE: 都不拥有 LPCTSTR lpName // 命名 ); // 创建成功返回互斥句柄 // 互斥句柄,也是可等候句柄- 在任何时间点上只有一个线程拥有互斥, 独占性和排他性
- 当任何线程都不拥有互斥,互斥有信号,任何一个线程拥有互斥,互斥就没有信号
 
- 
等候互斥 WaitFor... 函数 互斥的等候遵循谁先等候谁先获得 也就是加锁 
- 
释放互斥 BOOL ReleaseMutex( HANDLE hMutex // 互斥锁句柄 );
- 
关闭互斥句柄 CloseHandle
 
- 
demo
#include <windows.h>
#include <stdio.h>
HANDLE hmutex; // 接收互斥句柄 
DWORD CALLBACK TestProc(LPVOID pParam){
   char * pszText = (char *) pParam;
   int i ;
   while(1){
   	    WaitForSingleObject(hmutex,INFINITE);
	    for(i = 0;i<strlen(pszText);i++){
	   		printf("%c",pszText[i]);
	   		Sleep(125);
	   }
	   printf("\n");
	   ReleaseMutex(hmutex); 
   } 
}
int main(){
	hmutex = CreateMutex(NULL,FALSE,NULL); 
    DWORD nID1 = 0;
    DWORD nID2 = 0;
    char * pszText1 = "******";
    char * pszText2 = "------";
    HANDLE hThread1 = CreateThread(NULL,0,TestProc,pszText1,0,&nID1);
    HANDLE hThread2 = CreateThread(NULL,0,TestProc,pszText2,0,&nID2);
	getchar();
	CloseHandle(hmutex);
	return 0;
}
事件
- 
相关问题 线程之间的通知问题 
- 
事件的使用 - 
创建事件 HANDLE CreateEvent( LPSEURITY_ATTRIBUTES lpEventAttributes, // 安全属性 BOOL bManualReset, // 事件重置(复位)方式 有信号 -> 无信号 // TRUE 手动 // FALSE 自动 --> 读取信号一次就会自动复位 // 触发 无信号 ->有信号 BOOL bInitialState ,// 事件初始状态,TRUE 有信号 LPCTSTR lpName // 事件命名,可以为空 );// 创建成功返回事件句柄可等候句柄 事件的有信号无信号可控制 
- 
等候事件 WaitForSingleObject / WaitForMultipleObjects // 自动复位方式,会自动复位
- 
触发事件( 将事件设置为有信号状态) BOOL SetEvent( HANDLE hEvent //handle to event );
- 
复位事件( 将事件设置为无信号状态 ) BOOL ResetEvent( HANDLE hEvent );
- 
关闭事件 CloseHandle
 
- 
要小心事件的死锁问题
demo
#include <windows.h>
#include <stdio.h>
HANDLE g_hEvent = 0; // 接收事件句柄
DWORD CALLBACK PrintProc(LPVOID pParam){
	while(1){
		WaitForSingleObject(g_hEvent,INFINITE); // 等待信号 
		ResetEvent(g_hEvent); 
		printf("......\n");
	}
}
DWORD CALLBACK CtrlProc(LPVOID pParam){
	while(1){
		Sleep(1000);
		SetEvent(g_hEvent);
	}
} 
int main(){
	g_hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	DWORD nID = 0;
	HANDLE hThread[2] = {0};
	hThread[0] = CreateThread(NULL,0,PrintProc,NULL,0,&nID); 
	hThread[1] = CreateThread(NULL,0,CtrlProc,NULL,0,&nID);
	WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
	CloseHandle(g_hEvent);
	return 0; 
}
信号量
- 
相关的问题 作用类似于事件,解决通知的相关问题。 提供一个计数器,可以设置次数 
- 
信号量的使用 - 
创建信号量 HANDLE CreateSemaphore( LPSECTRITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性 LONG lInitialCount, // 初始化信号量数量 // 信号量计数值为0时,没有信号 // 信号量计数值不为0,有信号 LONG lMaximumCount, // 信号量最大个数 LPCTSTR lpName // 命名 );// 创建成功返回信号量句柄可等候句柄 
- 
等候信号量 WaitFor ... // 每等候通过一次,信号量的信号减1,直到为0阻塞
- 
给信号量指定计数值 BOOL ReleaseSemaphore( HANDLE hSemaphore, // 信号量句柄 LONG lReleaseCount ,// 释放数量 LPLONG lpPreviousCount // 返回的信息,返回释放前原来信号量的数量,可以为NULL );
- 
关闭句柄 CloseHandle
 
- 
demo
#include <windows.h>
#include <stdio.h>
HANDLE g_hSema = 0;// 保存信号量句柄
DWORD CALLBACK TestProc(LPVOID pParam){
	while(1){
		WaitForSingleObject(g_hSema,INFINITE);
		printf("*****\n");
	}
}
 
int main(){
	g_hSema = CreateSemaphore(NULL,3,10,NULL);
	DWORD nID = 0;
	HANDLE hThread = CreateThread(NULL,0,TestProc,NULL,0,&nID);
	getchar();
	ReleaseSemaphore(g_hSema,5,NULL);
	WaitForSingleObject(hThread,INFINITE);
	CloseHandle(g_hSema);	
	return 0;
}