Lock files可以用於進程間進行通訊。比如,我們想要讓某些資源被多個進程共用,有一個程式用於發布更新的資源,而其他一些程式可以使用最新的資源做一些事情。由於reader程式可能是一些batch file,所以不太可能使用一些比較進階的同步工具來鎖定我們需要發布的資源。這樣使用lock files將會是比較直接、簡單的方法。
我們需要用lock files來實現簡單的Reader-Writer鎖,也就是當有人需要進行寫操作時,所有其他動作都是不允許的。但是當有人進行讀操作時,只有讀操作時允許的,寫操作依然是被禁止的。
#include <windows.h> #include <cstdlib> #include <cstring> #include <iostream> #include <tchar.h> enum lock_mode { lm_shareread, lm_exclusive, lm_count};int main(int argc, char** argv) { if (argc >= 2) { lock_mode m; DWORD dwAccess; DWORD dwShareMode; if (strcmp(argv[1], "-r") == 0) { dwAccess = GENERIC_READ; dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE; // share read m = lm_shareread; } else if (strcmp(argv[1], "-w") == 0) { dwAccess = GENERIC_WRITE; dwShareMode = FILE_SHARE_DELETE; // do not share read or write, exclusive m = lm_exclusive; } else { std::cerr << "invalid argument/n"; return EXIT_FAILURE; } HANDLE hFile; hFile = CreateFile(_T("lock"), dwAccess, dwShareMode, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); if (hFile != INVALID_HANDLE_VALUE) {#ifdef _DEBUG char c; std::cin >> c;#endif if (m == lm_shareread) { std::cout << "read complete/n"; } else { std::cout << "write complete/n"; } CloseHandle(hFile); return EXIT_SUCCESS; } else { if (m == lm_shareread) { std::cerr << "Cannot read/n"; } else { std::cerr << "Cannot write/n"; } std::cerr << "Error code: " << GetLastError() << std::endl; return EXIT_FAILURE; } } else { std::cerr << "no arguments specified/n"; return EXIT_FAILURE; }}
這個程式接受2種參數,-r, -w,-r進行讀,-w進行寫,可以試著類比兩種file locks的情況。
這裡我們使用FILE_FLAG_DELETE_ON_CLOSE,由於file locks通常是臨時檔案,所以當最後一個檔案控制代碼關閉的時候,將會自動刪除這個檔案,而FILE_ATTRIBUTE_TEMPORARY是說,這是個臨時檔案,對它的寫入將不用寫回到磁碟上(不加也沒有關係,因為我們這裡不會有任何存取操作)。
在建立檔案時,我們使用了OPEN_ALWAYS。因為如果不存在,我們肯定需要建立一個檔案,但是如果已經存在,那麼我們希望直接開啟這個檔案。 如果將它們分開為2個操作: 1. 測試檔案是否存在 2. 開啟或者建立檔案
將會有race condition出現。假設我們測試完後發現檔案不存在,那麼我們決定建立檔案,但是此時另外一個程式也發現檔案不存在,也準備建立檔案,那麼其中一個建立操作必然會失敗,這裡我們想要的是atomic operation,而OPEN_ALWAYS正好保證了這種情況。