国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

深入淺出Win32多線程程序設(shè)計之基本概念

2019-11-17 05:09:09
字體:
供稿:網(wǎng)友
  引言

  從單進(jìn)程單線程到多進(jìn)程多線程是操作系統(tǒng)發(fā)展的一種必然趨勢,當(dāng)年的DOS系統(tǒng)屬于單任務(wù)操作系統(tǒng),最優(yōu)秀的程序員也只能通過駐留內(nèi)存的方式實現(xiàn)所謂的"多任務(wù)",而如今的Win32操作系統(tǒng)卻可以一邊聽音樂,一邊編程,一邊打印文檔。

  理解多線程及其同步、互斥等通信方式是理解現(xiàn)代操作系統(tǒng)的要害一環(huán),當(dāng)我們精通了Win32多線程程序設(shè)計后,理解和學(xué)習(xí)其它操作系統(tǒng)的多任務(wù)控制也非常輕易。許多程序員從來沒有學(xué)習(xí)過嵌入式系統(tǒng)領(lǐng)域聞名的操作系統(tǒng)VxWorks,但是立馬就能在上面做開發(fā),大概要歸功于平時在Win32多線程上下的功夫。

  因此,學(xué)習(xí)Win32多線程不僅對理解Win32本身有重要意義,而且對學(xué)習(xí)和領(lǐng)會其它操作系統(tǒng)也有觸類旁通的作用。

  進(jìn)程與線程

  先闡述一下進(jìn)程和線程的概念和區(qū)別,這是一個許多大學(xué)老師也講不清楚的問題。

  進(jìn)程(PRocess)是具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運行活動,是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個獨立單位。程序只是一組指令的有序集合,它本身沒有任何運行的含義,只是一個靜態(tài)實體。而進(jìn)程則不同,它是程序在某個數(shù)據(jù)集上的執(zhí)行,是一個動態(tài)實體。它因創(chuàng)建而產(chǎn)生,因調(diào)度而運行,因等待資源或事件而被處于等待狀態(tài),因完成任務(wù)而被撤消,反映了一個程序在一定的數(shù)據(jù)集上運行的全部動態(tài)過程。

  線程(Thread)是進(jìn)程的一個實體,是CPU調(diào)度和分派的基本單位。線程不能夠獨立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制。

  線程和進(jìn)程的關(guān)系是:線程是屬于進(jìn)程的,線程運行在進(jìn)程空間內(nèi),同一進(jìn)程所產(chǎn)生的線程共享同一內(nèi)存空間,當(dāng)進(jìn)程退出時該進(jìn)程所產(chǎn)生的線程都會被強制退出并清除。線程可與屬于同一進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源,但是其本身基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的信息(如程序計數(shù)器、一組寄存器和棧)。

  根據(jù)進(jìn)程與線程的設(shè)置,操作系統(tǒng)大致分為如下類型:

 ?。?)單進(jìn)程、單線程,MS-DOS大致是這種操作系統(tǒng);

 ?。?)多進(jìn)程、單線程,多數(shù)UNIX(及類UNIX的linux)是這種操作系統(tǒng);

  (3)多進(jìn)程、多線程,Win32(Windows NT/2000/XP等)、Solaris 2.x和OS/2都是這種操作系統(tǒng);

  (4)單進(jìn)程、多線程,VxWorks是這種操作系統(tǒng)。

  在操作系統(tǒng)中引入線程帶來的主要好處是:

 ?。?)在進(jìn)程內(nèi)創(chuàng)建、終止線程比創(chuàng)建、終止進(jìn)程要快;

 ?。?)同一進(jìn)程內(nèi)的線程間切換比進(jìn)程間的切換要快,尤其是用戶級線程間的切換。另外,線程的出現(xiàn)還因為以下幾個原因:

  (1)并發(fā)程序的并發(fā)執(zhí)行,在多處理環(huán)境下更為有效。一個并發(fā)程序可以建立一個進(jìn)程,而這個并發(fā)程序中的若干并發(fā)程序段就可以分別建立若干線程,使這些線程在不同的處理機上執(zhí)行。

 ?。?)每個進(jìn)程具有獨立的地址空間,而該進(jìn)程內(nèi)的所有線程共享該地址空間。這樣可以解決父子進(jìn)程模型中,子進(jìn)程必須復(fù)制父進(jìn)程地址空間的問題。

  (3)線程對解決客戶/服務(wù)器模型非常有效。

  Win32進(jìn)程

  1、進(jìn)程間通信(ipC)

  Win32進(jìn)程間通信的方式主要有:

  (1)剪貼板(Clip Board);

  (2)動態(tài)數(shù)據(jù)交換(Dynamic Data Exchange);

 ?。?)部件對象模型(Component Object Model);

  (4)文件映射(File Mapping);

 ?。?)郵件槽(Mail Slots);

  (6)管道(Pipes);

 ?。?)Win32套接字(Socket);

 ?。?)遠(yuǎn)程過程調(diào)用(Remote Procedure Call);

  (9)WM_COPYDATA消息(WM_COPYDATA Message)。

  2、獲取進(jìn)程信息

  在WIN32中,可使用在PSAPI .DLL中提供的Process status Helper函數(shù)幫助我們獲取進(jìn)程信息。

  (1)EnumProcesses()函數(shù)可以獲取進(jìn)程的ID,其原型為:

BOOL EnumProcesses(DWord * lpidProcess, DWORD cb, DWORD*cbNeeded);
  參數(shù)lpidProcess:一個足夠大的DWORD類型的數(shù)組,用于存放進(jìn)程的ID值;

  參數(shù)cb:存放進(jìn)程ID值的數(shù)組的最大長度,是一個DWORD類型的數(shù)據(jù);

  參數(shù)cbNeeded:指向一個DWORD類型數(shù)據(jù)的指針,用于返回進(jìn)程的數(shù)目;

  函數(shù)返回值:假如調(diào)用成功,返回TRUE,同時將所有進(jìn)程的ID值存放在lpidProcess參數(shù)所指向的數(shù)組中,進(jìn)程個數(shù)存放在cbNeeded參數(shù)所指向的變量中;假如調(diào)用失敗,返回FALSE。

  (2)GetModuleFileNameExA()函數(shù)可以實現(xiàn)通過進(jìn)程句柄獲取進(jìn)程文件名,其原型為:

DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,LPTSTR lpstrFileName, DWORD nsize);
  參數(shù)hProcess:接受進(jìn)程句柄的參數(shù),是HANDLE類型的變量;

  參數(shù)hModule:指針型參數(shù),在本文的程序中取值為NULL;

  參數(shù)lpstrFileName:LPTSTR類型的指針,用于接受主調(diào)函數(shù)傳遞來的用于存放進(jìn)程名的字符數(shù)組指針;

  參數(shù)nsize:lpstrFileName所指數(shù)組的長度;

  函數(shù)返回值:假如調(diào)用成功,返回一個大于0的DWORD類型的數(shù)據(jù),同時將hProcess所對應(yīng)的進(jìn)程名存放在lpstrFileName參數(shù)所指向的數(shù)組中;加果調(diào)用失敗,則返回0。

  通過下列代碼就可以遍歷系統(tǒng)中的進(jìn)程,獲得進(jìn)程列表:

//獲取當(dāng)前進(jìn)程總數(shù)
EnumProcesses(process_ids, sizeof(process_ids), &num_processes);
//遍歷進(jìn)程
for (int i = 0; i < num_processes; i++)
{
 //根據(jù)進(jìn)程ID獲取句柄
 process[i] = OpenProcess(PROCESS_QUERY_INFORMATION PROCESS_VM_READ, 0,
 process_ids[i]);
 //通過句柄獲取進(jìn)程文件名
 if (GetModuleFileNameExA(process[i], NULL, File_name, sizeof(fileName)))
  cout << fileName << endl;
}

  Win32線程

  WIN32靠線程的優(yōu)先級(達(dá)到搶占式多任務(wù)的目的)及分配給線程的CPU時間來調(diào)度線程。WIN32本身的許多應(yīng)用程序也利用了多線程的特性,如任務(wù)治理器等。

  本質(zhì)而言,一個處理器同一時刻只能執(zhí)行一個線程("微觀串行")。WIN32多任務(wù)機制使得CPU似乎在同時處理多個任務(wù)一樣,實現(xiàn)了"宏觀并行"。其多線程調(diào)度的機制為:

 ?。?)運行一個線程,直到被中斷或線程必須等待到某個資源可用;

  (2)保存當(dāng)前執(zhí)行線程的描述表(上下文);

 ?。?)裝入下一執(zhí)行線程的描述表(上下文);

 ?。?)若存在等待被執(zhí)行的線程,則重復(fù)上述過程。

  WIN32下的線程可能具有不同的優(yōu)先級,優(yōu)先級的范圍為0~31,共32級,其中31表示最高優(yōu)先級,優(yōu)先級0為系統(tǒng)保留。它們可以分成兩類,即實時優(yōu)先級和可變優(yōu)先級:

 ?。?)實時優(yōu)先級從16到31,是實時程序所用的高優(yōu)先級線程,如許多監(jiān)控類應(yīng)用程序;

 ?。?)可變優(yōu)先級從1到15,絕大多數(shù)程序的優(yōu)先級都在這個范圍內(nèi)。。WIN32調(diào)度器為了優(yōu)化系統(tǒng)響應(yīng)時間,在它們執(zhí)行過程中可動態(tài)調(diào)整它們的優(yōu)先級。

  多線程確實給應(yīng)用開發(fā)帶來了許多好處,但并非任何情況下都要使用多線程,一定要根據(jù)應(yīng)用程序的具體情況來綜合考慮。一般來說,在以下情況下可以考慮使用多線程:

 ?。?)應(yīng)用程序中的各任務(wù)相對獨立;

 ?。?)某些任務(wù)耗時較多;

 ?。?)各任務(wù)需要有不同的優(yōu)先級。

  另外,對于一些實時系統(tǒng)應(yīng)用,應(yīng)考慮多線程。

  Win32核心對象

  WIN32核心對象包括進(jìn)程、線程、文件、事件、信號量、互斥體和管道,核心對象可能有不只一個擁有者,甚至可以跨進(jìn)程。有一組WIN32 API與核心對象息息相關(guān):

 ?。?)WaitForSingleObject,用于等待對象的"激活",其函數(shù)原型為:

DWORD WaitForSingleObject(
 HANDLE hHandle, // 等待對象的句柄
 DWORD dwMilliseconds // 等待毫秒數(shù),INFINITE表示無限等待
);

  可以作為WaitForSingleObject第一個參數(shù)的對象包括:Change notification、Console input、Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread和Waitable timer。

  假如等待的對象不可用,那么線程就會掛起,直到對象可用線程才會被喚醒。對不同的對象,WaitForSingleObject表現(xiàn)為不同的含義。例如,使用WaitForSingleObject(hThread,…)可以判定一個線程是否結(jié)束;使用WaitForSingleObject(hMutex,…)可以判定是否能夠進(jìn)入臨界區(qū);而WaitForSingleObject (hProcess,… )則表現(xiàn)為等待一個進(jìn)程的結(jié)束。

  與WaitForSingleObject對應(yīng)還有一個WaitForMultipleObjects函數(shù),可以用于等待多個對象,其原型為:

DWORD WaitForMultipleObjects(DWORD nCount,const HANDLE* pHandles,BOOL bWaitAll,DWORD dwMilliseconds);
  (2)CloseHandle,用于關(guān)閉對象,其函數(shù)原型為:

BOOL CloseHandle(HANDLE hObject);
  假如函數(shù)執(zhí)行成功,則返回TRUE;否則返回FALSE,我們可以通過GetLastError函數(shù)進(jìn)一步可以獲得錯誤原因。

  C運行時庫

  在VC++6.0中,有兩種多線程編程方法:一是使用C運行時庫及WIN32 API函數(shù),另一種方法是使用MFC,MFC對多線程開發(fā)有強大的支持。
標(biāo)準(zhǔn)C運行時庫是1970年問世的,當(dāng)時還沒有多線程的概念。因此,C運行時庫早期的設(shè)計者們不可能考慮到讓其支持多線程應(yīng)用程序。
Visual C++提供了兩種版本的C運行時庫,-個版本供單線程應(yīng)用程序調(diào)用,另一個版本供多線程應(yīng)用程序調(diào)用。多線程運行時庫與單線程運行時庫有兩個重大差別:

  (1)類似errno的全局變量,每個線程單獨設(shè)置一個;

  這樣從每個線程中可以獲取正確的錯誤信息。

 ?。?)多線程庫中的數(shù)據(jù)結(jié)構(gòu)以同步機制加以保護(hù)。

  這樣可以避免訪問時候的沖突。


  Visual C++提供的多線程運行時庫又分為靜態(tài)鏈接庫和動態(tài)鏈接庫兩類,而每一類運行時庫又可再分為debug版和release版,因此Visual C++共提供了6個運行時庫。如下表:

C運行時庫庫文件Single thread(static link)libc.libDebug single thread(static link)Libcd.libMultiThread(static link)libcmt.libDebug multiThread(static link)libcmtd.libMultiThread(dynamic link)msvert.libDebug multiThread(dynamic link)msvertd.lib
  假如不使用VC多線程C運行時庫來生成多線程程序,必須執(zhí)行下列操作:

 ?。?)使用標(biāo)準(zhǔn) C 庫(基于單線程)并且只答應(yīng)可重入函數(shù)集進(jìn)行庫調(diào)用;

  (2)使用 Win32 API 線程治理函數(shù),如 CreateThread;

 ?。?)通過使用 Win32 服務(wù)(如信號量和 EnterCriticalSection 及 LeaveCriticalSection 函數(shù)),為不可重入的函數(shù)提供自己的同步。

  假如使用標(biāo)準(zhǔn) C 庫而調(diào)用VC運行時庫函數(shù),則在程序的link階段會提示如下錯誤:

error LNK2001: unresolved external symbol __endthreadex
error LNK2001: unresolved external symbol __beginthreadex


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 普兰县| 宜都市| 托克逊县| 黄大仙区| 林口县| 庆阳市| 巴东县| 淮阳县| 上饶县| 华池县| 手机| 敖汉旗| 嘉善县| 内丘县| 雷州市| 当涂县| 栾城县| 景泰县| 石屏县| 商河县| 大方县| 日照市| 民乐县| 敦化市| 深圳市| 灵川县| 天峻县| 华宁县| 宜川县| 湛江市| 兰考县| 清远市| 天门市| 博爱县| 彩票| 文登市| 封开县| 武穴市| 太谷县| 上饶县| 太谷县|