Win32学习笔记——线程

	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;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
仿多线程的效果一般有2种办法:第一种是通过定时器;第二种是启动多线程,不同模式下启动函数不同,mfc与API与WIN32下面注意点也是有区别的! VC启动一个新线程的三种方法,有需要的朋友可以参考下。 第一种AfxBeginThread() 用AfxBeginThread()函数来创建一个新线程来执行任务,工作者线程的AfxBeginThread的原型如下: CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,   LPVOID lParam,   int nPriority = THREAD_PRIORITY_NORMAL,   UINT nStackSize = 0,   DWORD dwCreateFlags = 0,   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL   );//用于创建工作者线程 返回值: 成功时返回一个指向新线程线程对象的指针,否则NULL。 pfnThreadProc : 线程的入口函数,声明一定要如下: UINT MyThreadFunction(LPVOID pParam),不能设置为NULL; pParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程. nPriority : 线程的优先级,一般设置为 0 .让它和主线程具有共同的优先级. nStackSize : 指定新创建的线程的栈的大小.如果为 0,新创建的线程具有和主线程一样的大小的栈 dwCreateFlags : 指定创建线程以后,线程有怎么样的标志.可以指定两个值: CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread 0 : 创建线程后就开始运行. lpSecurityAttrs : 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL, 那么新创建的线程就具有和主线程一样的安全性. 如果要在线程内结束线程,可以在线程内调用 AfxEndThread. 一般直接用AfxBeginThread(ThreadProc,this); 示例: UINT myproc(LPVOID lParam){CITTDlg *pWnd = (CITTDlg *)lParam; //将窗口指针赋给无类型指针pWnd->KMeansSegment(); //要执行的函数return 1;}void CITTDlg::KMeansSegment(){// 主要处理函数在这里写}void CITTDlg::OnKMeansSegment() //按钮点击执行{AfxBeginThread(myproc, (LPVOID)this);//启动新的线程} 注意,工作者线程的函数必须是全局函数或静态成员函数,不能是普通的成员函数。 第二种CreateThread()函数原型为:HANDLECreateThread( NULL, // 没有安全描述符 0, // 默认线程栈的大小 MyThreadProc, // 线程函数指针,即函数名 (LPVOID)&n, // 传递参数 NULL, // 没有附加属性 NULL // 不需要获得线程号码 ); CreatThread,它返回的是一个句柄;如果不需要再监视线程,则用CloseHandle()关闭线程句柄。 线程的函数必须定义为: DWORD WINAPI MyThreadProc(LPVOID pParameter); 下面演示多线程操作控件,点击一个Button然后运行一个线程,将字符串显示在CEdit控件里面; 示例: .h头文件struct hS {CString Tmp;CTestDlg *hWnd; };//定义全局结构体,用来传递自定义消息DWORD WINAPI ThreadProc(LPVOIDlpParam);//线程函数声明,全局函数public: CString chtmp; struct hS *hTmp;protected: HANDLE m_hThread;//线程句柄 CEdit m_Edit;.cpp实现文件//线程执行函数DWORD WINAPI ThreadProc(LPVOID lpParam){//在这里写处理函数struct hS *Tmp2;Tmp2 = (hS*)lpParam;// 操作: Tmp2->hWnd->m_Edit.SetWindowText( (LPTSTR)Tmp2->Tmp );}void CTestDlg::OnBnClickedButton1(){ hTmp->Tmp = chtmp; hTmp->hWnd = this;//关键是把this指针传进去 m_hThread =CreateThread(NULL,0,ThreadProc,hTmp,0,NULL);//创建新线程 CloseHandle(m_hThread );} 用CreateThread()函数创建线程将返回一个线程句柄,通过该句柄你可以控制和操作该线程,当你不用时可以一创建该线程后就关闭该句柄,有专门的函CloseHandle()。关闭句柄不代表关闭线程,只是你不能在外部控制该线程(比如,提前结束,更改优先级等)。在线程结束后,系统将自动清理线程资源,但并不自动关闭该句柄,所以线程结束后要记得关闭该句柄。 第三种_beginthread() 函数原型为:intptr_t _beginthread( void( *start_address )( void * ), //指向新线程调用的函数的起始地址 unsigned stack_size, //堆栈大小,设置0为系统默认值 void *arglist //传递给线程函数的参数,没有则为NULL ); 返回值: 假如成功,函数将会返回一个新线程的句柄,用户可以像这样声明一个句柄变量存储返回值:   HANDLE hStdOut = _beginthread( CheckKey, 0, NULL )。如果失败_beginthread将返回-1。所在库文件: #include 线程函数的定义: 对于_beginthread()创建的线程,其线程函数定义为: void ThreadPro(void * pArguments ); _beginthreadex()为_beginthread()的升级版。 总结:AfxBeginThread是MFC的全局函数,是对CreateThread的封装。 CreateThreadWin32 API函数,AfxBeginThread最终要调到CreateThread。而_beginthread是C的运行库函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值