熱點推薦:
您现在的位置: 電腦知識網 >> 操作系統 >> Windows系統管理 >> 正文

Windows平台下的多線程編程

2022-06-13   來源: Windows系統管理 

  線程是進程的一條執行路徑它包含獨立的堆棧和CPU寄存器狀態每個線程共享所有的進程資源包括打開的文件信號標識及動態分配的內存等一個進程內的所有線程使用同一個地址空間而這些線程的執行由系統調度程序控制調度程序決定哪個線程可執行以及什麼時候執行線程線程有優先級別優先權較低的線程必須等到優先權較高的線程執行完後再執行在多處理器的機器上調度程序可將多個線程放到不同的處理器上去運行這樣可使處理器任務平衡並提高系統的運行效率
  
  Windows是一種多任務的操作系統在Windows的一個進程內包含一個或多個線程位Windows環境下的Win API提供了多線程應用程序開發所需要的接口函數而利用VC中提供的標准C庫也可以開發多線程應用程序相應的MFC類庫封裝了多線程編程的類用戶在開發時可根據應用程序的需要和特點選擇相應的工具為了使大家能全面地了解Windows多線程編程技術本文將重點介紹Win API和MFC兩種方式下如何編制多線程程序
  
  多線程編程在Win方式下和MFC類庫支持下的原理是一致的進程的主線程在任何需要的時候都可以創建新的線程當線程執行完後自動終止線程; 當進程結束後所有的線程都終止所有活動的線程共享進程的資源因此在編程時需要考慮在多個線程訪問同一資源時產生沖突的問題當一個線程正在訪問某進程對象而另一個線程要改變該對象就可能會產生錯誤的結果編程時要解決這個沖突
  
  Win API下的多線程編程
  
  Win API是Windows操作系統內核與應用程序之間的界面它將內核提供的功能進行函數包裝應用程序通過調用相關函數而獲得相應的系統功能為了向應用程序提供多線程功能Win API函數集中提供了一些處理多線程程序的函數集直接用Win API進行程序設計具有很多優點: 基於Win的應用程序執行代碼小運行效率高但是它要求程序員編寫的代碼較多且需要管理所有系統提供給程序的資源用Win API直接編寫程序要求程序員對Windows系統內核有一定的了解會占用程序員很多時間對系統資源進行管理因而程序員的工作效率降低
  
   用Win函數創建和終止線程
  
  Win函數庫中提供了操作多線程的函數包括創建線程終止線程建立互斥區等在應用程序的主線程或者其他活動線程中創建新的線程的函數如下
  
  HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributesDWORD dwStackSizeLPTHREAD_START_ROUTINE lpStartAddressLPVOID lpParameterDWORD dwCreationFlagsLPDWORD lpThreadId);
  
  如果創建成功則返回線程的句柄否則返回NULL創建了新的線程後該線程就開始啟動執行了但如果在dwCreationFlags中使用了CREATE_SUSPENDED特性那麼線程並不馬上執行而是先掛起等到調用ResumeThread後才開始啟動線程在這個過程中可以調用下面這個函數來設置線程的優先權
  
  BOOL SetThreadPriority(HANDLE hThreadint nPriority);
  
  當調用線程的函數返回後線程自動終止如果需要在線程的執行過程中終止則可調用函數
  
  VOID ExitThread(DWORD dwExitCode);
  
  如果在線程的外面終止線程則可調用下面的函數
  
  BOOL TerminateThread(HANDLE hThreadDWORD dwExitCode);
  
  但應注意: 該函數可能會引起系統不穩定而且線程所占用的資源也不釋放因此一般情況下建議不要使用該函數
  
  如果要終止的線程是進程內的最後一個線程則線程被終止後相應的進程也應終止
  
   線程的同步
  
  在線程體內如果該線程完全獨立與其他線程沒有數據存取等資源操作上的沖突則可按照通常單線程的方法進行編程但是在多線程處理時情況常常不是這樣線程之間經常要同時訪問一些資源由於對共享資源進行訪問引起沖突是不可避免的為了解決這種線程同步問題Win API提供了多種同步控制對象來幫助程序員解決共享資源訪問沖突在介紹這些同步對象之前先介紹一下等待函數因為所有控制對象的訪問控制都要用到這個函數
  
  Win API提供了一組能使線程阻塞其自身執行的等待函數這些函數在其參數中的一個或多個同步對象產生了信號或者超過規定的等待時間才會返回在等待函數未返回時線程處於等待狀態此時線程只消耗很少的CPU時間使用等待函數既可以保證線程的同步又可以提高程序的運行效率最常用的等待函數是
  
  DWORD WaitForSingleObject(HANDLE hHandleDWORD dwMilliseconds);
  
  而函數WaitForMultipleObject可以用來同時監測多個同步對象該函數的聲明為
  
  DWORD WaitForMultipleObject(DWORD nCountCONST HANDLE *lpHandlesBOOL bWaitAllDWORD dwMilliseconds);
  
  ()互斥體對象
  
  Mutex對象的狀態在它不被任何線程擁有時才有信號而當它被擁有時則無信號Mutex對象很適合用來協調多個線程對共享資源的互斥訪問可按下列步驟使用該對象
  
  首先建立互斥體對象得到句柄
  
  HANDLE CreateMutex();
  
  然後在線程可能產生沖突的區域前(即訪問共享資源之前)調用WaitForSingleObject將句柄傳給函數請求占用互斥對象
  
  dwWaitResult = WaitForSingleObject(hMutexL);
  
  共享資源訪問結束釋放對互斥體對象的占用
  
  ReleaseMutex(hMutex);
  
  互斥體對象在同一時刻只能被一個線程占用當互斥體對象被一個線程占用時若有另一線程想占用它則必須等到前一線程釋放後才能成功
  
  ()信號對象
  
  信號對象允許同時對多個線程共享資源進行訪問在創建對象時指定最大可同時訪問的線程數當一個線程申請訪問成功後信號對象中的計數器減一調用ReleaseSemaphore函數後信號對象中的計數器加一其中計數器值大於或等於0但小於或等於創建時指定的最大值如果一個應用在創建一個信號對象時將其計數器的初始值設為0就阻塞了其他線程保護了資源等初始化完成後調用ReleaseSemaphore函數將其計數器增加至最大值則可進行正常的存取訪問可按下列步驟使用該對象
  
  首先創建信號對象
  
  HANDLE CreateSemaphore();
  
  或者打開一個信號對象
  
  HANDLE OpenSemaphore();
  
  然後在線程訪問共享資源之前調用WaitForSingleObject
  
  共享資源訪問完成後應釋放對信號對象的占用
  
  ReleaseSemaphore();
  
  ()事件對象
  
  事件對象(Event)是最簡單的同步對象它包括有信號和無信號兩種狀態在線程訪問某一資源之前需要等待某一事件的發生這時用事件對象最合適例如只有在通信端口緩沖區收到數據後監視線程才被激活
  
  事件對象是用CreateEvent函數建立的該函數可以指定事件對象的類和事件的初始狀態如果是手工重置事件那麼它總是保持有信號狀態直到用ResetEvent函數重置成無信號的事件如果是自動重置事件那麼它的狀態在單個等待線程釋放後會自動變為無信號的用SetEvent可以把事件對象設置成有信號狀態在建立事件時可以為對象命名這樣其他進程中的線程可以用OpenEvent函數打開指定名字的事件對象句柄
  
  ()排斥區對象
  
  在排斥區中異步執行時它只能在同一進程的線程之間共享資源處理雖然此時上面介紹的幾種方法均可使用但是使用排斥區的方法則使同步管理的效率更高
  
  使用時先定義一個CRITICAL_SECTION結構的排斥區對象在進程使用之前調用如下函數對對象進行初始化:
  
  VOID InitializeCriticalSection(LPCRITICAL_SECTION);
  
  當一個線程使用排斥區時調用函數EnterCriticalSection或者TryEnterCriticalSection;
  
  當要求占用退出排斥區時調用函數LeaveCriticalSection釋放對排斥區對象的占用供其他線程使用
  
  基於MFC的多線程編程
  
  MFC是微軟的VC開發集成環境中提供給程序員的基礎函數庫它用類庫的方式將Win API進行封裝以類的方式提供給開發者由於其快速簡捷功能強大等特點深受廣大開發者喜愛因此建議使用MFC類庫進行應用程序的開發
  
  在VC++附帶的MFC類庫中提供了對多線程編程的支持基本原理與基於Win API的設計一致但由於MFC對同步對象做了封裝因此實現起來更加方便避免了對象句柄管理上的煩瑣工作
  
  在MFC中線程分為兩種工作線程和用戶接口線程工作線程與前面所述的線程一致用戶接口線程是一種能夠接收用戶的輸入處理事件和消息的線程
  
   工作線程
  
  工作線程編程較為簡單設計思路與前面所講的基本一致: 一個基本函數代表了一個線程創建並啟動線程後線程進入運行狀態; 如果線程用到共享資源則需要進行資源同步處理這種方式創建線程並啟動線程時可調用函數
  
  CWinThread*AfxBeginThread( AFX_THREADPROC pfnThreadProc LPVOID pParamint nPriority= THREAD_PRIORITY_NORMALUINT nStackSize =DWORD dwCreateFlags= LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);參數pfnThreadProc是線程執行體函數函數原形為: UINT ThreadFunction( LPVOID pParam)
  
  參數pParam是傳遞給執行函數的參數 <
From:http://tw.wingwit.com/Article/os/xtgl/201311/9522.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.