一 Windows线程 1. Windows线程 Windows进程中可以执行代码的实体,Windows系统中可以调度的代码。 系统可以调度的执行代码,一个进程中至少有一个或多个线程。 2. 线程的特点 2.1 每个线程都有一个ID。 2.2 每个线程都有自己的安全属性。 2.3 每个线程有自己的一个栈。 3. 进程和线程多任务 多进程实现的多任务:由于进程地址空间是属于各自私有,内存和资源不能共享。 多线程实现的多任务:由于线程都是位于同一个进程的地址空间之内,内存和资源可以共享。 4. 线程的执行 线程的执行方式采用轮询方式执行。 二 线程的是使用 1. 定义线程的处理函数 DWORD WINAPI ThreadProc(LPVOID lpParameter) 2. 创建线程 CreateThread 3. 结束线程 ExitThread TerminateThread 4. 挂起线程 SuspendThread 5. 唤醒线程 ResuemThread 6. 等候线程结束 WaitForSingleObject() 7. 关闭线程句柄 CloseHandle(hThread) 三 线程局部存储 Thread Local Storage 1. 由于多个线程使用同一个变量,各个线程都对变量进行操作,那么变量的值会被不同的线程操作覆盖。 2. TLS 的使用 2.1 关键字的使用 _declspec(thread) ; _declspec(thread) TCHAR * g_pszText2 = NULL ; 2.2 TLS相关API 2.2.1 创建TLS索引 TlsAlloc 返回一个TLS索引号 2.2.2 设置值 TlsSetValue 2.2.3 获取值 TlsGetValue 2.2.4 释放 TlsFree
#include "stdafx.h"
#include <Windows.h>
TCHAR * g_pszText = NULL;
DWORD g_nTlsIndex = 0;
void Print()
{
wprintf(_T("g_pszTxt: %s\n"), g_pszText);
//从TLS索引中获取值
TCHAR * pszText = (TCHAR *)TlsGetValue(g_nTlsIndex) ;
wprintf(_T("pszText: %s\n"), pszText);
}
DWORD WINAPI PrintProc( LPVOID pParam )
{
TCHAR* pszText = (TCHAR*)pParam ;
g_pszText = new TCHAR [100] ;
wcscpy_s(g_pszText, 100, pszText) ;
//将值保存到TLS索引当中
TlsSetValue(g_nTlsIndex, pszText) ;
while(1)
{
Print();
Sleep(1000);
}
}
void Create()
{
HANDLE hThread = NULL ;
DWORD nThreadID = 0 ;
TCHAR szText1[] = _T("ThreadProc1") ;
hThread = CreateThread(NULL, 0, PrintProc, szText1, 0, &nThreadID) ;
TCHAR szText2[] = _T("ThreadProc2") ;
hThread = CreateThread(NULL, 0, PrintProc, szText2, 0, &nThreadID) ;
WaitForSingleObject(hThread,INFINITE) ;
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建SLS索引号
g_nTlsIndex = TlsAlloc() ;
//创建线程
Create() ;
//释放索引
TlsFree(g_nTlsIndex) ;
return 0;
}
二 线程同步 1. 多线程的问题 当线程挂起会保存寄存器的状态。 当线程开始会恢复寄存器的状态。 2. 同步机制 2.1 原子锁 2.2 临界区 2.3 事件 2.4 互斥 2.5 信号量 2.6 可等候定时器 3. 等候多个对象事件 WaitForMutipleObjects fWaitAll: TRUE - 等候每个句柄都有事件 FALSE - 等候其中一个句柄的事件 三 原子锁 1.作用 执行单个指令时,锁定操作不允许其他线程访问。 2. 用法 InterlockedIncreament ++运算 InterlockedDecrement --运算 InterlockedCompareExchange ?运算 四 临界区 1. 作用 线程在执行代码时,将代码锁定,不允许其他线程执行,只有该线程离开后,其他线程才能使用这个代码。 2. 使用 2.1 初始化临界区 InittializeCriticalSection 2.2 临界区加锁 EnterCriticalSection 2.3 临界区解锁 LeaveCriticalSection 2.4 释放临界区 DeleteCriticalSection 3. 和原子锁相比 原子锁是一条语句 临界区可以完成多条代码的锁定
// CriticalSection.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <conio.h>
CRITICAL_SECTION g_cs = {0} ;
void Print()
{
//进入临界区
EnterCriticalSection(&g_cs) ;
wprintf(_T("1 Long long long ..................................long long long\n")
_T("5 Long long long ..................................long long long\n"));
//离开临界区
LeaveCriticalSection(&g_cs) ;
}
DWORD WINAPI PrintProc(LPVOID pParam)
{
while (1)
{
Print() ;
Sleep(1000) ;
}
return 0 ;
}
void Create()
{
DWORD nThreadID = 0;
HANDLE hThread[2] = { NULL } ;
hThread[0] = CreateThread(NULL, 0, PrintProc, NULL, 0, &nThreadID) ;
hThread[1] = CreateThread(NULL, 0, PrintProc, NULL, 0, &nThreadID) ;
getch() ;
}
int _tmain(int argc, _TCHAR* argv[])
{
//初始化临界区
InitializeCriticalSection(&g_cs) ;
Create() ;
//删除临界区
DeleteCriticalSection(&g_cs) ;
return 0;
}
五 事件 1. 作用 通知的作用,当受到事件时,线程可以执行。否则线程将等候事件发生。 2. 事件的用法 2.1 创建一个事件 CreateEvent bManualReset - 事件重置方式, TRUE手动和FALSE自动重置 如果为FALSE,系统在等候到事件后,会自动将事件重置为无信号状态。 如果为TRUE,我们必须自己重置状态ResetEvent重置为无信号状态。 2.2 等候事件 WaitForSingleObject WaitForMutipleObjects 2.3 触发事件 SetEvent 2.4 关闭事件 CloseHandle 2.5 重置事件 ResetEvent 2.6 其他函数 OpenEvent PluseEvent
#include "stdafx.h"
#include <Windows.h>
#include <conio.h>
HANDLE g_hEvent = NULL ;
DWORD WINAPI ThreadSend(LPVOID lParam)
{
while(1)
{
//触发事件
SetEvent(g_hEvent) ;
Sleep(1000) ;
}
return 0 ;
}
DWORD WINAPI ThreadRecive(LPVOID lParam)
{
while (1)
{
//等候事件通知
WaitForSingleObject(g_hEvent, INFINITE) ;
wprintf(_T("Hello Event: %p\n"), g_hEvent) ;
}
return 0 ;
}
void Create()
{
DWORD dwThreadId = 0 ;
HANDLE hThread[2] = { NULL } ;
hThread[0] = CreateThread(NULL, 0, ThreadSend, NULL, 0, &dwThreadId);
hThread[1] = CreateThread(NULL, 0, ThreadRecive, NULL, 0, &dwThreadId) ;
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建事件
g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
Create() ;
getch() ;
CloseHandle(g_hEvent) ;
return 0;
}
六 互斥量 1. 作用 多个线程同时只能有一个执行。 2. 互斥量的使用 2.1 创建互斥量 CreateMutex bInitialOwner - TRUE, 表示当前创建互斥量线程拥有互斥。 FALSE,为不拥有。 2.2 等候互斥 WaitForSingleObject WaitForMutipleObject 2.3 重置互斥 ReleaseMutex 2.4 关闭互斥 CloseHandle 2.5 使用互斥线程,按照谁先等候谁先拥有互斥量的规则顺序执行。 2.6 其他函数 OpenMutex 打开互斥
#include "stdafx.h"
#include <Windows.h>
#include <conio.h>
HANDLE g_hMutex = NULL ;
DWORD WINAPI ThreadProc1( LPVOID pParam )
{
while(1)
{
//等候互斥
WaitForSingleObject(g_hMutex,INFINITE) ;
wprintf(_T("ThreadProc1----------\n")) ;
Sleep(500) ;
//释放互斥
ReleaseMutex(g_hMutex) ;
}
return 0 ;
}
DWORD WINAPI ThreadProc2( LPVOID pParam )
{
while(1)
{
WaitForSingleObject(g_hMutex,INFINITE) ;
wprintf(_T("----------ThreadProc2\n")) ;
Sleep(500) ;
//释放互斥量
ReleaseMutex(g_hMutex) ;
}
return 0 ;
}
DWORD WINAPI ThreadProc3( LPVOID pParam )
{
while(1)
{
WaitForSingleObject(g_hMutex,INFINITE) ;
wprintf(_T("----ThreadProc3-----\n")) ;
Sleep(500) ;
//释放互斥量
ReleaseMutex(g_hMutex) ;
}
return 0 ;
}
void Create()
{
DWORD dwThreadID = 0 ;
HANDLE hThread[3] = { NULL } ;
hThread[0] = CreateThread(NULL, 0, ThreadProc1, NULL, 0, &dwThreadID) ;
hThread[1] = CreateThread(NULL, 0, ThreadProc2, NULL, 0, &dwThreadID) ;
hThread[2] = CreateThread(NULL, 0, ThreadProc3, NULL, 0, &dwThreadID) ;
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建互斥量
g_hMutex = CreateMutex(NULL, FALSE, NULL) ;
Create() ;
_getch() ;
CloseHandle(g_hMutex) ;
return 0;
}
七 信号量 1. 作用 通知的作用,和事件类似。但是与事件不同。事件只维护一个值0或者1。 信号量维护一个变量,0时无信号。大于0有信号。 2. 信号量的使用 2.1 创建信号量 CreateSemaphore 2.2 等候信号量 WaitForSingleObject WaitForMultipleObject 2.3 释放信号量 ReleaseSemaphore 2.4 关闭信号量 CloseHandle 2.5 打开信号量 OpenSemaphore
#include "stdafx.h"
#include <Windows.h>
#include <conio.h>
HANDLE g_hSemaphore = NULL ;
DWORD WINAPI ThreadSend( LPVOID pParam )
{
while (1)
{
TCHAR ch = _getch() ;
switch(ch)
{
case '1':
//释放信号
ReleaseSemaphore(g_hSemaphore, 1, NULL) ;
break;
case '5':
ReleaseSemaphore(g_hSemaphore, 5, NULL) ;
break;
}
//ReleaseSemaphore(g_hSemaphore, 1, NULL) ;
//Sleep(1000) ;
}
return 0 ;
}
DWORD WINAPI ThreadRecive( LPVOID pParam )
{
while(1)
{
//等待信号
WaitForSingleObject(g_hSemaphore, INFINITE) ;
wprintf(_T("Hello Semaphore\n")) ;
Sleep(100) ;
}
return 0 ;
}
void Create()
{
DWORD dwThread = 0 ;
HANDLE hThread[2] = { NULL } ;
hThread[0] = CreateThread(NULL, 0, ThreadSend, NULL, 0, &dwThread) ;
hThread[1] = CreateThread(NULL, 0, ThreadRecive, NULL, 0, &dwThread) ;
WaitForMultipleObjects(2,hThread, TRUE, INFINITE) ;
}
int _tmain(int argc, _TCHAR* argv[])
{
g_hSemaphore = CreateSemaphore(NULL, 5, 10, NULL) ;
Create() ;
CloseHandle(g_hSemaphore) ;
return 0;
}
八 可等候定时器 1. 作用 是一个更加精确的系统定时器。 能够达到100ns级别。 2. 定时器的使用 2.1 创建定时器 CreateWaitableTimer 2.2 设置定时器 SetWaitialbeTimer *pDueTime定时器第一次触发的事件100ns。正值表示绝对时间。负值表示相对于现在的时间间隔。 lPeriod 后续每次触发的时间。取0不再有后续触发。大于0按照时间间隔触发。 pfnCompletionRourine APC处理函数 lpArgToCompletionRoutine APC参数 fResume 计算机休眠标志 2.2 等候定时器 WaitForSingleObject WaitForMultipleObject 2.3 关闭定时器 CloseHandle
#include "stdafx.h"
#include <Windows.h>
HANDLE g_hTimer = NULL ;
DWORD WINAPI TimerThread( LPVOID pParam )
{
while( 1 )
{
WaitForSingleObject(g_hTimer, INFINITE) ;
wprintf(_T("HELLO TIMER\n")) ;
}
return 0 ;
}
void Create()
{
//创建定时器
g_hTimer = CreateWaitableTimer(NULL, FALSE, NULL) ;
//设置定时器
UINT64 nDueTime = -100000000 ;
SetWaitableTimer(g_hTimer, (PLARGE_INTEGER)&nDueTime, 1000,
NULL, NULL, FALSE) ;
DWORD dwThreadID = 0 ;
HANDLE hThread = CreateThread( NULL, 0, TimerThread, NULL, 0, &dwThreadID) ;
WaitForSingleObject(hThread, INFINITE) ;
//关闭定时器
CloseHandle(g_hTimer) ;
}
int _tmain(int argc, _TCHAR* argv[])
{
Create() ;
return 0;
}