Windows线程是可以执行的代码的实例。
系统是以线程为单位调度程序,一个程序中可以有多个线程,实现多任务的处理。主线程只能有一个。
Windows线程的特点
线程的调度
操作系统将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
#include
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
#include
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
#include
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
#include
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;
}