前言
微軟鼓勵大家多用線程,而弱化子程序的使用,是以和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釋放資源