Windows线程开发
Posted muxisuibi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows线程开发相关的知识,希望对你有一定的参考价值。
Windows线程开发
1.线程基础
-
Windows线程是可以执行的代码实例。系统十一线程为单位调度程序。一个程序当中可以有多个线程,实现多个任务的处理。
-
Windows线程的特点:
- 线程都具有1个ID
- 每个线程都具有自己的内存栈
- 同一进程中的线程使用同一个地址空间
-
线程的调度
操作系统将CPU的执行时间划分成时间片,依次根据时间片执行不同的线程。线程轮询:线程A->线程B->线程A......
2.创建线程
-
创建线程
HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, //安全属性 SIZE_T dwStackSize, //线程栈的大小 LPTHREAD_START_ROUTINE lpStartAddress, //线程处理函数的函数地址 LPVOID lpParameter, //传递给线程处理函数的参数 DWORD dwCreationFlags, //线程创建方式 LPDWORD lpThreadId //创建成功,返回线程的ID );创建成功,返回线程句柄
-
定义线程处理函数
DWORD WINAPI ThreadProc( LPVOID lpParameter //创建线程时,传递给线程的参数 );
例子:
#include <Windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc(LPVOID param){
char* pszText = (char*) param;
while(1){
printf("%s\\n",pszText);
Sleep(1000);
}
return 0;
}
int main(){
DWORD pid = 0;
char* pszText="******";
HANDLE hThread = CreateThread(NULL,0,ThreadProc,pszText,0,&pid);
getchar();
return 0;
}
3.线程挂起/销毁
-
挂起
DWORD SuspendThread( HANDLE hThread //handle to thread );
-
唤醒
DWORD ResumeThread( HANDLE hThread //handle to thread );
例子:
#include <Windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc(LPVOID param){
char* pszText = (char*) param;
while(1){
printf("%s\\n",pszText);
Sleep(1000);
}
return 0;
}
DWORD CALLBACK ThreadProc2(LPVOID param){
char* pszText = (char*) param;
while(1){
printf("%s\\n",pszText);
Sleep(1000);
}
return 0;
}
int main(){
DWORD pid = 0;
char* pszText="<<<<<<";
HANDLE hThread = CreateThread(NULL,0,ThreadProc,pszText,0,&pid); //创建的线程立即执行
char* pszText2 = ">>>>>>";
HANDLE hThread2 = CreateThread(NULL,0,ThreadProc2,pszText2,CREATE_SUSPENDED,&pid); //创建的线程挂起
getchar();
SuspendThread(hThread);
ResumeThread(hThread2);
getchar();
return 0;
}
4.线程相关操作
-
结束指定线程
BOOL TerminateThread( HANDLE hTread, //handle to thread DWORD dwExitCode //exit code );
-
结束函数所在的线程
VOID ExitThread( DWORD dwExitCode //exit code for this thread );
-
获取当前线的ID
GetCurrentThreadId();
-
获取当前线程的句柄
GetCurrentThread();
-
等候单个句柄有信号
VOID WaitForSingleObject( HANDLE handle, //句柄BUFF的地址 DWORD dwMillseconds //等候时间INFINITE(无限大) );
-
同时等候多个句柄有信号
DWORD WaitForMultipleObjects( DWORD nCount, //句柄数量 CONST HANDLE *lpHandles, //句柄BUFF的地址 BOOL bWaitAll, //等候方式 DWORD dwMillisenconds //等候时间INFINITE ); bWaitAll - 等候方式: TRUE - 表示所有句柄都有信号,才结束等候 FALSE - 表示句柄中只要有1个有信号,就结束等候
5.线程同步
5.1 原子锁
-
相关问题
多个线程对同一个数据进行原子操作,会产生结果丢失。比如执行++运算时。
-
错误代码分析
当线程A执行g_value++时,如果线程切换时间正好是线程A将值保存到g_value之前线程B继续执行g_value++,那么当线程A再次切换回来之后,会将原来线程A保存的值保存到g_value上,线程B进行的加法操作被覆盖。
-
使用原子锁函数
InterlockedIncrement
InterlockedDecrement
InterlockedCompareExchange
InterlockedExchange
...
原子锁的实现:直接对数据所在的内存操作,并且 在任何一个瞬间只能有一个线程访问。
5.2 互斥
-
相关的问题
多线程下代码或资源的共享使用。
-
互斥的使用
-
创建互斥
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性 BOOL bInitialOwner, //初始的拥有者 TRUE/FALSE LPCTSTR lpName //命名 ); 创建成功返回互斥句柄
-
等候互斥
WaitFor... 互斥的等候遵循谁先等候谁先获取。
-
释放互斥
BOOL ReleaseMutex( HANDLE hMutex //handle to mutex );
-
关闭互斥句柄
CloseHandle( HANDLE hMutex );
-
例子:
#include <Windows.h>
#include <stdio.h>
HANDLE g_hMutex = 0; //获得互斥句柄
DWORD CALLBACK ThreadProc(LPVOID param){
char* pszText = (char*) param;
while(1){
/*printf("%s\\n",pszText);
Sleep(1000);*/
WaitForSingleObject(g_hMutex,INFINITE);
for(int i = 0; i < strlen(pszText); i++){
printf("%c",pszText[i]);
Sleep(125);
}
printf("\\n");
ReleaseMutex(g_hMutex);
}
return 0;
}
DWORD CALLBACK ThreadProc2(LPVOID param){
char* pszText = (char*) param;
while(1){
/*printf("%s\\n",pszText);
Sleep(1000);*/
WaitForSingleObject(g_hMutex,INFINITE);
for(int i = 0; i < strlen(pszText); i++){
printf("%c",pszText[i]);
Sleep(125);
}
printf("\\n");
ReleaseMutex(g_hMutex);
}
return 0;
}
int main(){
g_hMutex = CreateMutex(NULL,FALSE,NULL);
DWORD pid = 0;
char* pszText="<<<<<<";
HANDLE hThread = CreateThread(NULL,0,ThreadProc,pszText,0,&pid); //创建的线程立即执行
char* pszText2 = ">>>>>>";
HANDLE hThread2 = CreateThread(NULL,0,ThreadProc2,pszText2,0,&pid);
getchar();
CloseHandle(g_hMutex);
return 0;
}
5.3 事件
-
相关问题
程序之间的通知的问题。
-
事件的使用
-
创建事件
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性 BOOL bManualReset, //事件重置(复位)方式,TRUE手动,FALSE自动 BOOL bInitialState, //事件初始状态,TRUE有信号 LPCTSTR lpName //事件命名 );创建成功返回事件句柄
-
等候事件
WaitForSingleObject
/WaiteForMultipleObjects
-
触发事件(将事件设置成有信号状态)
BOOL SetEvent( HANDLE hEvent //handle to event );
-
复位事件(将事件设置成无信号状态)
BOOL ResetEvent( HANDLE hEvent //handle to event );
-
关闭事件
CloseHandle(HANDLE hEvent);
小心事件的死锁
例子:
#include <Windows.h> #include <stdio.h> HANDLE g_hEvent = 0; //获得事件句柄 DWORD CALLBACK PrintProc(LPVOID param){ while(1){ WaitForSingleObject(g_hEvent,INFINITE); ResetEvent(g_hEvent); printf("*********\\n"); } return 0; } DWORD CALLBACK CtlProc(LPVOID param){ while(1){ Sleep(1000); SetEvent(g_hEvent); } return 0; } int main(){ g_hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); DWORD pid = 0; HANDLE hThread[2] = {0}; hThread[0] = CreateThread(NULL,0,PrintProc,NULL,0,&pid); hThread[0] = CreateThread(NULL,0,CtlProc,NULL,0,&pid); WaitForMultipleObjects(2,hThread,TRUE,INFINITE); getchar(); CloseHandle(g_hEvent); return 0; }
-
5.4 信号量
-
相关的问题
类似于事件,解决通知的相关问题。但提供一个计数器,可以设置次数。
-
信号量的使用
-
创建信号量
HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //安全属性 LONG lInitialCount, //初始化信号量数量 LONG lMaximumCount, //信号量的最大值 LPCTSTR lpName //命名 ); 创建成功返回信号量句柄
-
等候信号量
WaitFor... 每等候通过一次,信号量的信号减1,直到为0阻塞
-
给信号量指定计数值
BOOL ReleaseSemaphore( HANDLE hSemaphore, //信号量句柄 LONG lReleaseCount, //释放数量 LPLONG lpPreviousCount //释放前原来信号量的数量,可以为NULL );
-
关闭句柄
CloseHandle(HANDLE handle);
#include <Windows.h> #include <stdio.h> HANDLE g_hSema = 0; //信号量句柄 DWORD CALLBACK TestProc(LPVOID param){ while(1){ WaitForSingleObject(g_hSema,INFINITE); printf("*********\\n"); } return 0; } int main(){ g_hSema = CreateSemaphore(NULL,3,10,NULL); DWORD pid = 0; HANDLE hThread = CreateThread(NULL,0,TestProc,NULL,0,&pid); getchar(); ReleaseSemaphore(g_hSema,5,NULL); WaitForSingleObject(hThread,INFINITE); CloseHandle(g_hSema); return 0; }
-
以上是关于Windows线程开发的主要内容,如果未能解决你的问题,请参考以下文章
newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段