從單線程到多線程

進程(Process)是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,是系統進行資源分配和調度的一個獨立單位。程序只是一組指令的有序集合,它本身沒有任何運行的含義,只是一個靜態實體。而進程則不同,它是程序在某個數據集上的執行,是一個動態實體。它因創建而產生,因調度而運行,因等待資源或事件而被處於等待狀態,因完成任務而被撤消,反映了一個程序在一定的數據集上運行的全部動態過程。

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

  線程和進程的關係是:線程是屬於進程的,線程運行在進程空間內,同一進程所產生的線程共享同一內存空間,當進程退出時該進程所產生的線程都會被強制退出並清除。線程可與屬於同一進程的其它線程共享進程所擁有的全部資源,但是其本身基本上不擁有系統資源,只擁有一點在運行中必不可少的信息(如程序計數器、一組寄存器和棧),進程並不真正得運行程序,他只是分配資源得單位,只有線程纔是真正得運行體 ,所以一個進程最少有一個主線程。 

在操作系統中引入線程帶來的主要好處是:

  (1)在進程內創建、終止線程比創建、終止進程要快;

  (2)同一進程內的線程間切換比進程間的切換要快,尤其是用戶級線程間的切換。另外,線程的出現還因爲以下幾個原因:

  (1)併發程序的併發執行,在多處理環境下更爲有效。一個併發程序可以建立一個進程,而這個併發程序中的若干併發程序段就可以分別建立若干線程,使這些線程在不同的處理機上執行。

  (2)每個進程具有獨立的地址空間,而該進程內的所有線程共享該地址空間。這樣可以解決父子進程模型中,子進程必須複製父進程地址空間的問題。

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


Win32進程間通信的方式主要有:

  (1)剪貼板(Clip Board);

  (2)動態數據交換(Dynamic Data Exchange);//DDE是一種動態數據交換機制(Dynamic Data ExchangeDDE)。使用DDE通訊需要兩個Windows應用程序,其中一個作爲服務器處理信息,另外一個作爲客戶機從服務器獲得信息。客戶機應用程序向當前所激活的服務器應用程序發送一條消息請求信息,服務器應用程序根據該信息作出應答,從而實現兩個程序之間的數據交換。不太常用得東東- -#

  (3)部件對象模型(Component Object Model);//COMComponent Object Model,組件式對象模型),是組件之間相互接口的規範,是OLE和ActiveX的共同基礎,其作用是使各軟件組件和應用軟件能夠用一種統一的標準方式進行交互。COM不是一種面向對象的語言,而是一種與源代碼無關的二進制標準。COM所建立的是一個軟件模塊與另一個軟件模塊之間的鏈接,而當這種鏈接建立之後,模塊間就可以通過稱之爲“接口”的機制來進行通信。COM標準增加了保障系統和組件完整的安全機制,並擴展到分佈式環境。
基於分佈式環境下的COM被稱爲DCOM(Distributed COM,分佈式組件對象模型)。DCOM是ActiveX的基礎,它實現了COM對象與遠程計算機上的另一個對象之間直接進行交互。DCOM規範定義了分散對象創建和對象間通信機制,規範本身不依賴於任何特定編程語言和操作系統,但目前該標準只在Microsoft Windows平臺實現。


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

  (5)郵件槽(Mail Slots);

  (6)管道(Pipes);

  (7)Win32套接字(Socket);

  (8)遠程過程調用(Remote Procedure Call);

  (9)WM_COPYDATA消息(WM_COPYDATA Message)。

2、獲取進程信息

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

  (1)EnumProcesses()函數可以獲取進程的ID,其原型爲:

BOOL EnumProcesses(DWORD * lpidProcess, DWORD cb, DWORD*cbNeeded);


  參數lpidProcess:一個足夠大的DWORD類型的數組,用於存放進程的ID值;

  參數cb:存放進程ID值的數組的最大長度,是一個DWORD類型的數據;

  參數cbNeeded:指向一個DWORD類型數據的指針,用於返回進程的數目;

  函數返回值:如果調用成功,返回TRUE,同時將所有進程的ID值存放在lpidProcess參數所指向的數組中,進程個數存放在cbNeeded參數所指向的變量中;如果調用失敗,返回FALSE。


(2)GetModuleFileNameExA()函數可以實現通過進程句柄獲取進程文件名,其原型爲:

DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,LPTSTR lpstrFileName, DWORD nsize);


  參數hProcess:接受進程句柄的參數,是HANDLE類型的變量;

  參數hModule:指針型參數,在本文的程序中取值爲NULL;

  參數lpstrFileName:LPTSTR類型的指針,用於接受主調函數傳遞來的用於存放進程名的字符數組指針;

  參數nsize:lpstrFileName所指數組的長度;

  函數返回值:如果調用成功,返回一個大於0的DWORD類型的數據,同時將hProcess所對應的進程名存放在lpstrFileName參數所指向的數組中;加果調用失敗,則返回0。

Win32線程

  WIN32靠線程的優先級(達到搶佔式多任務的目的)及分配給線程的CPU時間來調度線程。WIN32本身的許多應用程序也利用了多線程的特性,如任務管理器等。

  本質而言,一個處理器同一時刻只能執行一個線程("微觀串行")。WIN32多任務機制使得CPU好像在同時處理多個任務一樣,實現了"宏觀並行"。其多線程調度的機制爲:

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

  (2)保存當前執行線程的描述表(上下文);

  (3)裝入下一執行線程的描述表(上下文);

  (4)若存在等待被執行的線程,則重複上述過程。

  WIN32下的線程可能具有不同的優先級,優先級的範圍爲0~31,共32級,其中31表示最高優先級,優先級0爲系統保留。它們可以分成兩類,即實時優先級和可變優先級:

  (1)實時優先級從16到31,是實時程序所用的高優先級線程,如許多監控類應用程序;

  (2)可變優先級從1到15,絕大多數程序的優先級都在這個範圍內。。WIN32調度器爲了優化系統響應時間,在它們執行過程中可動態調整它們的優先級。

Win32核心對象

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

(1)WaitForSingleObject,用於等待對象的"激活",其函數原型爲:

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

  可以作爲WaitForSingleObject第一個參數的對象包括:Change notification、Console input、Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread和Waitable timer。不同得對象有不同得含義,Mutex能否進入臨界區,Thread線程是否結束.

DWORD WaitForMultipleObjects(DWORD nCount,const HANDLE* pHandles,BOOL bWaitAll,DWORD dwMilliseconds);

nCount 等待得數目個數,pHandles句柄數組,bWaitAll是否等待所有對象都有效時才返回,dwMilliseconds等待得時間

(2)CloseHandle,用於關閉對象,其函數原型爲:

BOOL CloseHandle(HANDLE hObject);

 

C運行時庫

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

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

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

  (2)多線程庫中的數據結構以同步機制加以保護。

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

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

C運行時庫 庫文件
Single thread(static link) libc.lib
Debug single thread(static link) Libcd.lib
MultiThread(static link) libcmt.lib
Debug multiThread(static link) libcmtd.lib
MultiThread(dynamic link) msvert.lib
Debug multiThread(dynamic link) msvertd.lib

  如果不使用VC多線程C運行時庫來生成多線程程序,必須執行下列操作:

  (1)使用標準 C 庫(基於單線程)並且只允許可重入函數集進行庫調用;

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

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

  如果使用標準 C 庫而調用VC運行時庫函數,則在程序的link階段會提示如下錯誤:

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

VC中在工程-設置-C/C++-code generation-Use run-time library

分別是單線程版,多線程靜態DLL版,多線程動態DLL版,都有DEBUG與RELEASE兩種

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章