はい、もちろん、これは生産者と消費者のモデルのバリエーションです。
Threadここでは、 やのようないくつかの基本的なビルディング ブロックを使用できますAutoResetEvent。「プロデューサー」はログから行を読み取り、それらをファイルに投稿し (代わりにメモリ内バッファーを使用できますか?)、他のスレッドにそれらを読み取るように通知します。
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
}
これにより、ファイルを読み取るコンシューマーと、さらにログを読み取り、次のバッチを準備するプロデューサーとの間で、ある程度の並列処理が可能になります。
プロデューサーがログの処理を終了すると、ファイルに特別な終了メッセージを入れて、正常に終了するようにコンシューマーに通知できます。
これは 1 つの戦略であり、かなり低レベルでエラーが発生しやすいものです。共有ファイルを完全にスキップして、BlockingCollectionの形式でメモリ内バッファを使用できます。
ProducerTask数行のテキストを保持するクラスを定義します。
class ProducerTask 
{
    public String[] Lines { get; set; }
}
このタスクは一度に 500 行を保持します。
次に、次のようTaskに and BlockingCollection(.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
}
はるかにシンプルでエレガント。