-----------------------------------------------------------------------------
----------------------2016.09.22---------------------------------------------
線程是系統內核對象之一。
內核對象是系統內核分配的一個內存塊,該內存塊描述的是一個數據結構,其成員負責維護對象的各種信息。
內核對象的數據只能由系統內核來訪問。
常見的係統內核對象有:事件對象、文件對象、作業對象、互斥對象、管道對象、進程對象和線程對象。
共有屬性:
1.引用計算屬性->內核對象在進程中創建,創建時的使用計數為1,其他進程訪問該對象時,使用計數遞增1.當其使用計數為零時,系統撤銷該內核對象。
2.安全屬性->用安全描述符來表示,安全描述符描述了內核對象的創建者,有權訪問與使用的對象,能否被繼承等。
進程是一個正在運行的程序實例。
可以理解為一個容器,提供空間,執行程序的代碼由線程實現。
線程存在於進程中,負責執行進程地址空間中的代碼。
主線程:進程創建的時候,系統自動為進程創建的線程,用戶在主線程創建其他線程,主線程結束則進程結束。
線程的創建函數:Create Thread,_beginthreadex,AfxBeginThread。
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//線程的安全屬性,可為NULL
SIZE_T dwStackSize,//線程棧的最大大小,可忽略
LPTHREAD_START_ROUTINE lpStartAddress,//線程函數,線程運行時,執行的線程入口函數--------->DWORD ThreadProd(LPVOID lpParameter);
LPVOID lpParameter,//向線程函數傳遞的參數
DWORD dwCreationFlags,//線程創建的標記
LPDWORD lpThreadId//整形指針,用於接收線程的ID。
)
返回值:若函數執行成功,返回線程句柄,否則返回NULL。
創建線程程序的組成:
1)包含的必要文件:要包含Windows.h文件和iostream.h文件
2)線程入口函數
3)main函數:主線程的入口函數。
-----------------------------------------------------------------------------
_beginthreadex(
void *security,//安全
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist, unsigned initflag,
unsigned *thrdaddr );
//第1個參數:安全?性,NULL?默認安全?性
//第2個參數:指定線程堆棧的大小。如果為0,該線程堆棧大小和創建它的線程的大小相同。一般用0
//第3個參數:指定線程函數的地址,也就是線程?用運行的函數地址(用函數名稱即可,函數名稱就表示地址)
//第4個參數:指向該線程的??的指針,可以通??入?象的指?,在線程函數中再轉化為???的指針
//第5個參數:線程初始狀態,0:立即執行;CREATE_SUSPEND:suspended(?挂)
//第6個參數:用于??線程ID的地址
AfxBeginThread
-------------------------------------------------------------------------------------------------
創建線程的步驟:
1.創建對話框;
2.添加變量;
3.定義線程函數;
4.創建線程;
5.對話框關閉時釋放線程對象;
----------------------------------------------------------------------------------------
CWindThread類封裝了對線程的支持
該類提供了兩種類型線程,
工作者線程:線程中沒有消息循環,主要在後台進行計算或完成某些功能
用戶界面線程;具有消息循環,可處理從系統接收的消息
成員:
1.m_bAutoDelete:用於確定在線程終止時,線程對象是否自動被釋放;
2.m_hThread:表示線程對象關聯的線程句柄;
3.m_hThreadID:用於記錄線程ID;
4.m_pMainWnd用於表示應用程序的主窗口
5.m_pActiveWnd若線程是OLE服務器的一部分,該成員表示容器應用程序主窗口;
6.CreatedThread創建線程,
7.GetMainWnd獲取應用程序的窗口指針。
8.ResumeThread用於重新喚醒線程。將線程的掛起計數減1,若掛起計數為0,開始執行該線程。
若執行成功,返回線程的掛起計數,若返回為1,線程立刻執行。
9.SuspendThread用于掛起線程。
若執行成功,返回之前的掛起數。
10.ExitThread該函數用於結束當前的線程。
11.TerminateThread強制終止線程的執行。
------------------------------------------------------------------------------------
多線程應用程序中最容易出現的問題就是資源訪問衝突。
線程同步可用:事件對象、信號量對象、臨界區對象、互斥對象來實現。
------------------------------------------------------------------------------
事件對象實現線程同步:
----------------------
人工重置事件對象,自動重置事件對象。
人工重置:可以同時有多個線程等待到事件對象、成為可調度線程。
自動重置:等待該事件對象的多個線程只能有一個線程成為可調度線程。
----------------------------------------------------------------
1.CreateEvent:創建一個事件對象;
2.SetEvent:將事件設置為通知狀態;
3.ResetEvent:將事件設置為未通知狀態;
4.WaitForSingleObject:在設計線程同步時,要使用該函數來等待內核對象的狀態;
源代碼:
int number = 1;
HANDLE hEvent;//定義事件句柄
unsigned long _stdcall ThreadProc1(void* lpParameter)//線程函數
{
long count;
while(number<100)
{
WaitForSingleObject(hEvent,INFINITE);//等待事件對象為有信號狀態
printf("Thread 1 : %d\n",number);
number++;
Sleep(100);
SetEvent(hEvent);//設置事件為有信號狀態
}
return 0 ;
}
----------------------------------------------------------------------------
使用信號量對象實現
------------------
屬於系統內核對象之一,包含又使用計數。當使用計數為0時,信號量對象屬於無信號狀態;大於0 時,信號量對象處於有信號狀態。
1.CreateSemaphore:創建一個信號量對象;
2.ReleaseSemaphore:用於遞增信號量的使用計數;
源代碼:
int number = 1;
HANDLE hDemaphore;//信號量句柄
unsigned long _stdcall ThreadProc1(void* lpParameter)
{
long count;
while(number<100)
{
WaitForSingleObject(hDemaphore,INFINITE);//等待信號量為有信號狀態
printf("Thread 1 : %d\n",number);
number++;
Sleep(100);
ReleaseSemaphore(hDemaphore,1,&count);//使信號量有信號&count用於返回之前信號量的使用計數
}
return 0 ;
}
----------------------------------------------------------------------------------------------
使用臨界區對象實現
--------------------
1.InitializeCriticalSection:用於初始化臨界區對象
在使用臨界區對象時,首先需要定義一個臨界區對象,然後進行初始化
2.EnterCriticalSection:用於等待臨界區對象的所有權;
3.LeaveCriticalSection用於釋放臨界區對象的所有權。
4.DeleteCriticalSection:用於釋放為臨界區對象分配的相關資源,是臨界區對象不再可用。
源代碼:
int number = 1;
CRITICAL_SECTION Critical;//定義臨界句柄
unsigned long _stdcall ThreadProc1(void* lpParameter)
{
long count;
while(number<100)
{
EnterCriticalSection(&Critical);//獲取臨界區對象的所有權
printf("Thread 1 : %d\n",number);
number++;
Sleep(100);
LeaveCriticalSection(&Critical);//釋放臨界區對象的所有權
}
return 0 ;
}
-----------------------------------------------------------------------------------------------
使用互斥對象實現
-----------------
互斥對象使線程擁有對某個資源的絕對訪問權。
互斥對象主要包含:使用數量、線程ID(當前擁有互斥對象的線程)和遞歸計數器(線程擁有互斥對象的次數)等信息。
使用方式:當互斥對象為零時:表示互斥對象不被任何線程所擁有,此時系統會發出該互斥對象的通知信號,
等待互斥對象的某個線程將會擁有蓋互斥對象,同時互斥對象的線程ID為擁有該互斥對象的線程ID。
當互斥對象不為零時:表示當前線程擁有該互斥對象,系統不會發出該互斥對象的通知信號,
其他等待互斥對象的線程將繼續等待,知道擁有互斥對象的線程釋放互斥對象的所有權。
1.CreateMutex:創建一個互斥對象,返回所創建的互斥對象的句柄;
參數一:指向結構體SECURITY_ATTRIBUTES的指針;
參數二:BOOL 指定互斥對象初始的擁有者;
參數三:指定互斥對象的名稱,若為NULL,則創建一個匿名的互斥對象。
2.ReleaseMutex:釋放互斥對象的所有權;
參數:HANDLE型,需要釋放的互斥對象的句柄。
源代碼:
int number = 1;
HANDLE hMutex;//互斥對象句柄
unsigned long _stdcall ThreadProc1(void* lpParameter)
{
long count;
while(number<100)
{
WaitForSingleObject(hMutex,INFINITE);//等待互斥對象的所有權
printf("Thread 1 : %d\n",number);
number++;
Sleep(100);
ReleaseMutex(hMutex);//釋放互斥對象的所有權
}
return 0 ;
}
------------------------------------------------------------------------------------------------------------------
WaitForSingleObject函數
等待直到指定的對象處於有信號狀態或超時返回。
原型:
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle, //被等待的對象句柄;
__in DWORD dwMilliseconds //超時時間
);
-------------------------------------------------------------------------------------------
WaitForMultipleObjects函數
等待直到一個或所有指定的對象處於有信號狀態或超時。
原型:
DWORD WINAPI WaitForMultipleObjects(
__in DWORD nCount, //表示lpHandles指向的數組中對象句柄的數量,最大值為 MAXIMUM_WAIT_OBJECTS;
__in const HANDLE *lpHandles, //指向包含一組句柄對象的數組;
__in BOOL bWaitAll, //為TRUE,表示數組lpHandles中所有對象變為有信號狀態才返回;為FALSE,表示任一對象變為有信號狀態即返回;
__in DWORD dwMilliseconds //意義同WaitForSingleObject;
--------------------------------------------------------------------------------------------------