天天看點

windows基礎程式設計 - 程序和線程

前言

微軟鼓勵大家多用線程,而弱化子程序的使用,是以和unix不同,windows下程序的通信很少,記憶體映射檔案是一種。
           

程序

  • 程序環境資訊(程序上下文)

    每個程序啟動時系統都會生成相關的環境表,擷取裡面的環境變量可使用下面函數

    GetEnvironmentStrings FreeEnvironmentStrings 可以獲得該環境表的首位址

    SetEnvironmentVariable GetEnvironmentVariable 可以設定和得到環境變量的值

  • 擷取程序ID和程序句柄

    GetCurrentProcessId 擷取id

    GetCurrentProcess 獲得句柄,但是一個假句柄,值為-1,可正常使用

    OpenProcess 通過id獲得程序句柄,通常拿來獲得别的程序的句柄,也可調用OpenProcess(GetCurrentProcessId)獲得本程序真實句柄

  • 建立和結束程序

    BOOL CreateProcess(

    LPCTSTR lpApplicationName,應用程式全路徑名

    LPTSTR lpCommandLine, // 指令行參數

    LPSECURITY_ATTRIBUTES lpProcessAttributes, // 安全屬性 設為NULL

    LPSECURITY_ATTRIBUTES lpThreadAttributes, // 線程安全屬性NULL

    BOOL bInheritHandles, // 繼承辨別 NULL

    DWORD dwCreationFlags, // 建立方式 給0立即啟動

    LPVOID lpEnvironment, // 設定環境資訊 可為NULL

    LPCTSTR lpCurrentDirectory, // 設定工作目錄 可為NULL

    LPSTARTUPINFO lpStartupInfo, // 儲存起始資訊 需放入結構體位址

    LPPROCESS_INFORMATION lpProcessInformation // 建立的程序相關資訊,需放入結構體位址

    );

    ExitProcess 可以結束目前程序

    TerminateProcess 可以結束别的程序

    CloseHandle 将句柄置為 -1,程序不結束

    • 程序間的等候,即阻塞函數等待别的程序傳回

      DWORD WaitForSingleObject(

      HANDLE hHandle, // 程序句柄

      DWORD dwMilliseconds // 等待時間(INFINITE為無限長)

      );

      DWORD WaitForMultipleObjects(

      DWORD nCount, // 句柄數量

      CONST HANDLE *lpHandles, // 存放句柄的數組

      BOOL fWaitAll, // 等候方式TRUE等待所有 FALSE任何一個

      DWORD dwMilliseconds // 等待時間(INFINITE為無限長)

      );

      這兩個等候的函數一個可以等待單個程序,一個可以等候多個,裡頭的HANDLE其實可以不光隻是程序,也可以是線程,隻要是帶信号的句柄,這些句柄包括

      Change notification

      Console input 控制台輸入

      Event 事件

      Job

      Mutex 互斥

      Process 程序

      Semaphore 信号

      Thread 線程

      Waitable timer 可等候定時器

線程

程序如果對應電腦的記憶體,線程對應着電腦的CPU,線程也就是執行的代碼的執行個體。
系統是以線程為機關排程程式。
線程的排程: 将CPU的執行時間劃分成時間片,依次根據時間片執行不同的線程。
           

- 建立

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, //安全屬性

DWORD dwStackSize, // 線程棧大小為0向1M靠攏

LPTHREAD_START_ROUTINE lpStartAddress, // 線程處理函數

LPVOID lpParameter, // 處理函數參數

DWORD dwCreationFlags, //建立方式 挂起還是執行

LPDWORD lpThreadId // 接收的線程ID

);

- 結束 TerminateThread / ExitThread

結束後依舊需要調用CloseHandle釋放句柄資源

- 挂起/執行 SuspendThread ResumeThread

- 線程資訊 GetCurrentThreadId / GetCurrentThread

線程同步

線程同步技術是解決線程之間的資源競争和線程之間的協調工作。

其中,原子鎖、臨界區(段)、互斥 是給線程間加鎖,

  • 原子鎖

    直接對一個資料的記憶體操作,任一時間隻有一個線程通路該記憶體,可對這個資料進行增,減,改變數值

    InterlockedIncrement, InterlockedExchange, InterlockedDecrement

  • 臨界區

    可以鎖定一段代碼,防止多個線程同時使用該段代碼

    VOID InitializeCriticalSection(

    LPCRITICAL_SECTION lpCriticalSection // 臨界區結構體的位址

    ); //初始化一個臨界區

    VOID EnterCriticalSection(

    LPCRITICAL_SECTION lpCriticalSection

    ); //進入臨界區,放在要鎖定的代碼前

    VOID LeaveCriticalSection(

    LPCRITICAL_SECTION lpCriticalSection //

    ); //離開臨界區,放在鎖定的代碼結尾

    VOID DeleteCriticalSection(

    LPCRITICAL_SECTION lpCriticalSection

    ); //釋放臨界區資源

  • 互斥

    用于多線程下代碼或資源的共享使用

    HANDLE CreateMutex(

    LPSECURITY_ATTRIBUTES lpMutexAttributes,

    // 安全屬性

    BOOL bInitialOwner, // 初始擁有着,TRUE立刻獲得互斥鎖

    LPCTSTR lpName // 互斥名

    ); //傳回互斥句柄

    一個程序調用WaitForSingleObject時,如果持鎖,則無需等待,否則等待持鎖線程調用ReleaseMutext時立刻獲得互斥鎖

    CloseHandle 可以釋放互斥鎖句柄資源,OpenMutex可以根據互斥名獲得互斥鎖句柄,也可以使用在兩個程序間的通信。

    注: 互斥和臨界區的差別,

    臨界區 - 運作在使用者态,執行效率高,隻能在同一個程序中使用

    互斥 - 運作在核心态,執行效率低,可以通過命名方式跨程序使用(配合記憶體映射檔案)

  • 事件

    事件用于程式之間的通知的問題,是最常用的線程同步技術,事件句柄也分為有信号和無信号兩種狀态,無信号時會被WaitFor..函數等待,而SetEvent和ResetEvent可以手動設定事件句柄的信号狀态

    HANDLE CreateEvent(

    LPSECURITY_ATTRIBUTES lpEventAttributes,

    // 安全屬性

    BOOL bManualReset, // 手動還是自動複位

    BOOL bInitialState, // 初始狀态(有無信号)

    LPCTSTR lpName // 事件名字

    );

    另一程序調用WaitFor..函數等待時間句柄變為有信号狀态,如果是自動複位,會在調用結束後信号立馬變成無信号狀态,如果是手動,需要在調用結束後使用ResetEvent将信号置為無信号狀态

    不使用以後使用CloseHandle關閉事件句柄

  • 信号量

    類似于事件,解決通知的相關問題,可以提供一個計數器,設定信号有效的次數

    HANDLE CreateSemaphore(

    LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

    // 安全屬性

    LONG lInitialCount, // 初始計數值

    LONG lMaximumCount, // 最大值

    LPCTSTR lpName // 信号量名字

    );

    當一個線程調用WaitFor..函數會使信号量計數值減1,直到該值為0這個信号量會變為無信号狀态。使用ReleaseSemaphore可以重置信号量的計數值。使用結束後依舊使用CloseHandle釋放資源