首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

防止無視窗 Windows 程式重複執行:Mutex 最佳實踐

     編輯:VC 教學

傳統做法用 FindWindow 檢查視窗類別/標題,但無視窗程式(服務、Console、背景工具)無法適用。使用核心物件 Mutex (互斥體) 是通用、優雅、可靠的解決方案。

核心代碼


#include 

HANDLE hMutex = CreateMutex(
    NULL,                   // 預設安全性
    FALSE,                  // 初始不擁有
    _T("Global\\MyAppSingleInstanceMutex") // 命名 Mutex,跨 Session 可見
);

if (hMutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
    // Mutex 已存在 = 另一實例正在執行
    return FALSE; // 直接退出
}

// 正常執行主邏輯...
// 程式結束前釋放(系統自動回收,但建議顯式釋放)
ReleaseMutex(hMutex);
CloseHandle(hMutex);

關鍵點解析

  • 命名 Mutex:字串名稱使其成為全域核心物件,所有進程可開啟同一 Mutex。加上 Global\\ 前綴確保跨 Terminal Services Session 可見(服務/系統帳號下關鍵)。
  • CreateMutex 回傳:若 Mutex 已存在,回傳有效控制碼但 GetLastError() == ERROR_ALREADY_EXISTS。此即判斷重複執行的依據。
  • 自動清理:進程結束時系統自動釋放 Mutex,無殘留風險。
  • 比 FindWindow 優勢:無視窗、跨 Session、不依賴視窗類別/標題、不可被偽造視窗欺騙。

進階:限制最多 N 個實例並行

使用 Semaphore (訊號量) 取代 Mutex:


HANDLE hSem = CreateSemaphore(NULL, N, N, _T("Global\\MyAppMaxNSemaphore"));
if (hSem == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
    // 嘗試等待信號
    if (WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0)
        return FALSE; // 已達上限
}
// 執行中...
ReleaseSemaphore(hSem, 1, NULL);
CloseHandle(hSem);

初始/最大計數均設為 N,WaitForSingleObject(hSem, 0) 非阻塞嘗試獲取信號,失敗即表示已達上限。

最佳實踐清單

  1. Mutex 名稱使用 GUID 或公司/產品專屬前綴,避免衝突:Global\\{Company.Product.Component.GUID}。
  2. 在 main/WinMain/ServiceMain 最開頭執行檢查。
  3. GUI 程式若檢測到重複,可選擇啟動既有實例視窗(FindWindow + PostMessage 通知)而非單純退出。
  4. Console 程式直接退出並輸出提示訊息。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved