2012-06-01 43 views
1

我正在構建的應用程序從某個源讀取日誌並將其顯示在網格上。日誌的大小可以是幾MB到幾GB。爲了防止任何內存問題,我一次使用網格和分頁500行。這是我希望做的事:兩個線程之間交替

我想創建一個線程,將讀取日誌,並將它們寫入文件每次約500線,然後發出信號日誌已被寫入另一個線程。然後另一個線程將讀取該文件並在網格上顯示這些線併發出已完成讀取的第一個線程的信號。這一直持續到沒有更多的日誌被寫入文件。

是否可以在這樣的線程之間切換?

回答

2

是的,當然,這是producer-consumer model的變化。

你可以在這裏使用一些基本的積木一樣ThreadAutoResetEvent。 「生產者」讀取日誌,並將它們發佈行到一個文件中(也許你可以使用一個內存緩衝區,而不是?),然後通知其他線程閱讀:

AutoResetEvent consumerEvent = new AutoResetEvent(false); 
AutoResetEvent producerEvent = new AutoResetEvent(false); 

// producer code 
while(/* lines still available */) 
{ 
    // read 500 lines 
    // write to shared file 
    consumerEvent.Set(); // signal consumer thread 
    producerEvent.WaitOne(); // wait to be signaled to continue 
} 

和消費者的代碼:

while(/* termination not received */) 
{ 
    consumerEvent.WaitOne(); // wait for the producer to finish  
    // read lines from file and put them in the grid 
    producerEvent.Set(); // allow producer to read more logs 
} 

這將允許消費者閱讀文件和生產者閱讀更多日誌和準備下一批次之間的某種程度的並行性。

當製片人已與日誌完成了它可以在文件中把一個特殊的終止消息的信號,消費者正常退出。

這是一個戰略,這是相當低的水平,而且容易出錯。您可以完全跳過共享文件並使用BlockingCollection形式的內存緩衝區。

定義ProducerTask類來保存幾行文本:

class ProducerTask 
{ 
    public String[] Lines { get; set; } 
} 

此任務將容納500線在同一時間。

然後使用TaskBlockingCollection(.NET 4.0+)如下:

BlockingCollection<ProducerTask> buffer = new BlockingCollection<ProducerTask>(1); 

// producer task 
while(/* lines still available */) 
{ 
    // read 500 lines 
    ProducerTask p = new ProducerTask(); 
    buffer.Add(p); // this will block until the consumer takes the previous task 
} 

// consumer task 
while(/* termination not received */) 
{ 
    ProducerTask p = buffer.Take(); // blocks if no task is available 
    // put the lines in the grid 
} 

更加簡潔大方。

+0

謝謝,這正是我所尋找的。但我不認爲我可以使用內存緩衝區,因爲可以一次讀取的500行是可變的;它可以是任何數字。此外,我不想在內存中保存那麼多的數據,因爲應用程序還有其他的東西。 – Albert

0

從都鐸的很好的答案跟隨着你也可以看看TPL Dataflow它提供了一個非常乾淨的構建模塊實現生產者 - 消費者模式。