2017-02-13 87 views
0

我想從不同的線程(類似於日誌記錄)追加(寫入附加)到一個文件,因此不需要進程間鎖定。C++ -mutex或flock fcntl.h只鎖定寫操作

我已經在fcntl.h中研究了flock,它說羣可以在進程間執行粒度鎖定,在我的情況下這不是必需的。

char* file = "newfile.txt"; 
int fd; 
struct flock lock; 

printf("opening %s\n", file); 
fd = open(file, O_APPEND); 
if (fd >= 0) { 
    memset(&lock, 0, sizeof (lock)); 
    lock.l_type = F_WRLCK; 
    fcntl(fd, F_SETLKW, &lock); 
    //do my thing here 
    lock.l_type = F_UNLCK; 
    fcntl(fd, F_SETLKW, &lock); 
    close(fd); 
} 

會有開銷,因爲它可以做粒度鎖定和進程間鎖定嗎?當程序崩潰時會發生什麼情況?

我現在的選擇是互斥,

static std::mutex fileMutex; 
fileMutex.lock(); 
//do my thing here  
fileMutex.unlock(); 

是否還好時,互斥方法作爲同步(或鎖定)走的是隻在過程(僅多線程)需要,

或者是它可以在fcntl.h中用flock實現代碼嗎?

+1

在O_APPEND模式下打開! –

回答

1

您可能不需要任何鎖定。

讓您的open()電話與O_APPEND標誌設置,因爲@ Jean-BaptisteYunès在評論中提到。

然後使用單個的write()調用寫入您的數據。 POSIX保證如果文件以附加模式打開,則個別的write()操作將是原子操作。Per the POSIX standard

如果文件狀態標誌的O_APPEND標誌被設置,文件偏移 應當被設置爲之前每個寫該文件並沒有 的端部插入的文件修改操作改變 之間應發生文件偏移量和寫入操作。 [重點煤礦]

你唯一的問題是如何處理的部分write() - 在一個單一的write()操作不寫的所有請求的數據。該標準要求每個write()操作都是原子操作 - 它不能保證寫入34 MB的請求將導致寫入整個34 MB。根據我的經驗,部分write()調用實際文件根本不會發生,直到write()調用請求移動很多字節 - 我從來沒有觀察到在1 MB以下的文件上的任何單個IO操作上的部分write()結果 - 而我已經完成了許多大型組織的SAN安裝和基準測試。

因此,如果您將write()的調用限制在PIPE_BUF或更少的字節(在Linux上),幾乎肯定可以避免所有鎖定,並讓內部內部鎖定解決您的問題。

有關詳細信息,請參閱以下內容:

Is file append atomic in UNIX?

請務必閱讀從那裏鏈接的問題了。

+0

如果寫入超過PIPE_BUF,大小可以輕易超過。現在我只能想到帶有流寫入的互斥鎖。 –

+0

@ fury.slay由於您在Linux上運行,如果您控制整個平臺(包括您將要寫入的文件系統),則必須進行測試並找出實際限制。請參閱http://stackoverflow.com/questions/10650861如果您在Solaris或AIX上,幾乎可以肯定每個寫操作安全地超過1 MB(請注意,在ZFS上的鏈接 - 從Solaris - 每個寫入()'原子......)對於更高版本的Linux,你*可能*。 –

+0

我可以在我的系統上測試,但應用程序捆綁在用戶的不同類型的linux操作系統上運行,所以我不會對安全性有任何保證。糾正我,如果我錯了。 –

1

首先,你需要澄清多線程與多進程:

多個線程:我建議使用一個互斥。您還可以通過將日誌消息添加到內存緩衝區的末尾來提高效率,並且只使用互斥鎖保護對該緩衝區的訪問。然後,您可以使用另一個線程或某個常規維護函數將緩衝區刷新到文件,而無需在I/O進行時鎖定其他線程,並且不鎖定文件。對文件的訪問將不會受到互斥鎖或文件鎖的保護,因爲它只能由單個線程訪問。

(既然你表明沒有進程間通信,我建議走這條路)

多個進程:您必須使用一些鎖機制,由所有進程,例如可見您建議的文件鎖定。

Both:使用兩種機制。嘗試僅將文件鎖定絕對最短時間。

側節點:

多線程編程的第一條規則是不是「使用互斥體」,它是「儘量不被多個線程訪問數據」,甚至是「儘量不使用多線程,除非出於性能原因絕對必要「(例如,對於異步操作,您總是可以不使用線程)。

+0

我已經提到,有**沒有進程間通信(沒有多進程) –

+0

所以你建議,如果多線程互斥比羊羣好得多,並且沒有必要爲羣,你不是嗎? –

+0

@ fury.slay:是的,絕對。你可以在你的文件操作中加入一個互斥鎖。這在功能上是足夠和正確的,但速度很慢。所以我建議只對每個特定線程的文件進行訪問(因此不需要文件I/O的互斥體),然後使用共享內存緩衝區(字符串或字節隊列或任何您擁有的)來保護一個互斥體。 –