2009-12-16 60 views
2

我有這個工具,其中一個單一的類似日誌的文件被多個進程寫入。同時寫入文件

我想要達到的目標是在第一次打開文件時截斷文件,然後讓幾個打開的進程完成所有寫操作。 所有的寫操作都是系統刷新和互斥保護的,這樣我就不會出現混亂的輸出。

首先,進程創建文件,然後啓動一系列其他進程,一次一個,然後打開文件並寫入文件(主控制器有時會插入其他內容;從屬進程可能或可能不要開放和寫作)。

我希望儘可能不要使用已存在的更多IPC(我現在所做的只是寫入一個popen創建的管道)。我無法訪問其他CRT和Win32 API的外部庫,並且我不想開始編寫序列化代碼。

下面是一些代碼,其中顯示出我已經走了:

// open the file. Truncate it if we're the 'master', append to it if we're a 'slave' 
std::ofstream blah(filename, ios::out | (isClient ? ios:app : 0)); 

// do stuff... 

// write stuff 
myMutex.acquire(); 
blah << "stuff to write" << std::flush; 
myMutex.release(); 

好了,這不工作:雖然從過程的輸出是有序的預期,何師傅寫或者是聚集在一起或者在錯誤的地方,當它存在時。

我有兩個問題:給thestream的構造函數提供的標誌組合是正確的嗎?無論如何,我的方向是否正確?

+1

你還記錄一個時間戳嗎?如果是這樣,你可以看到排序是否正確。也許你的日誌記錄是正確的,但你的主進程正在做你沒想到的事情 – Toad 2009-12-16 16:42:02

+0

/我踢自己。時間戳揭示了事實:這些事件並不按照我認爲的那樣發生。謝謝你的提示 ! – 2009-12-16 18:36:28

回答

1

正如reinier所建議的,問題不在於我使用這些文件的方式,而在於程序的行爲方式。

fstreams做得很好。

我錯過了主從機之間的同步(前者假定某個特定操作是同步的,而不是)。

編輯:哦,還有一個打開標誌的問題。使用ios :: out打開文件的過程沒有根據需要移動文件指針(擦除其他進程正在寫入的文本),並且在寫入cout時使用seekp()完全擰緊了輸出,因爲代碼的另一部分使用了cerr。

我的最終解決方案是保持互斥鎖和flush,並且對於主進程,在ios :: out模式下打開文件(創建或截斷文件),關閉它並使用ios重新打開它:應用程序。

0

如何創建該互斥鎖?
爲了這個工作,這需要是一個有名的互斥體,這樣兩個進程實際上鎖定在同一個事物上。
您可以檢查您的互斥鎖實際上是否正確地使用一小段代碼將其鎖定在一個進程中,另一個進程嘗試獲取它。

+0

哦,爲了簡潔起見,我實際上放棄了創作部分。它是一個有名的互斥體,它可以正常工作。 – 2009-12-16 16:34:24

1

如果您將從多個線程向日志寫入大量數據,則需要重新考慮設計,因爲所有線程都會在嘗試獲取互斥鎖時阻塞,並且通常不需要你的線程被阻止工作,所以他們可以登錄。在這種情況下,您希望編寫您的工作線程來將條目記錄到隊列中(這隻需要在內存中移動東西),並且有一個專用線程將條目從隊列中取出並寫入輸出。這樣你的工作線程就會盡可能短地被阻塞。

通過使用異步I/O,你可以做得比這更好,但這會變得更棘手。

+0

我想這將是一個明智的方法,即使對於多進程設計......但我需要實現一些進程間通信,我不想這樣做。 – 2009-12-16 18:35:29

0

我建議阻止文本在釋放互斥之前完全寫入文件。我有一些實例,來自一個任務的文本被來自更高優先級線程的文本中斷;看起來不太漂亮。

此外,將格式轉換爲逗號分隔格式,或者可以輕鬆加載到電子表格中的某種格式。包含線程標識和時間戳。文本行的交錯顯示線程是如何交互的。 ID參數允許您按線程排序。時間戳可用於顯示順序訪問以及持續時間。以電子表格友好的格式進行書寫將允許您使用外部工具分析日誌文件,無需編寫任何轉換實用程序。這對我非常有幫助。

+0

我認爲std :: flush確保在返回之前完成寫入操作(我的準獨特用例是寫入本地文件)(並且它的工作至今)。 時間戳的確向我展示了問題所在。 – 2009-12-18 15:17:39

1

我做了一個'lil日誌系統,它有自己的過程,並將處理寫作過程,這個想法是相當模糊的。使用日誌的進程只是將它們發送到日誌進程將嘗試寫入文件的待處理隊列。這就像批處理在任何實時渲染應用程序。這樣你就可以擺脫太多的打開/關閉文件操作。如果我可以,我會添加示例代碼。

+0

非常簡單的確,絕對是下一次我需要它的探索選項! – 2010-01-07 16:20:39

0

一個選項是使用ACE :: logging。它有一個高效的併發日誌記錄實現。