2012-06-01 3 views
1

Приложение, которое я создаю, считывает журналы из некоторого источника и отображает их на сетке. Журналы могут быть от нескольких МБ до нескольких ГБ. Чтобы предотвратить любые проблемы с памятью, я использую сетку и пейджинг через журналы по 500 строк за раз. Это то, что я надеюсь сделать:Переключение между двумя потоками

Я хочу создать поток, который будет читать журналы и записывать их в файл около 500 строк каждый раз, а затем сигнализировать другой поток, который был записан в журнале. Затем другой поток будет читать файл и отображать строки в сетке и сигнализировать первый поток, который он закончил читать. это продолжается до тех пор, пока в файл не будет записано больше журналов.

Можно ли переключаться между потоками следующим образом?

ответ

2

Да, конечно, это вариант producer-consumer model.

Здесь можно использовать некоторые основные строительные блоки, например 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 
} 

Это позволит в некоторой степени параллельности между потребителем чтение файла и продюсер читает больше журналов и готовит следующую партию.

Когда производитель закончил с журналами, он может поместить в файл специальное сообщение о завершении, чтобы сигнализировать потребителю о выходе из строя.

Это одна из стратегий, и она довольно низкоуровневая и подвержена ошибкам. Вы можете полностью пропустить общий файл и использовать буфер в памяти в виде BlockingCollection.

Определить ProducerTask класс провести несколько строк текста:

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

Эта задача будет держать 500 строк за один раз.

Затем используйте Task и 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 
} 

Гораздо более простой и элегантный.

+0

Спасибо, это именно то, что я искал. Я не думаю, что я мог бы использовать буфер в памяти, хотя, потому что 500 строк, которые могут быть прочитаны за раз, являются переменными; это может быть любое число. Кроме того, я бы не захотел хранить в памяти столько данных, как есть другие вещи, которые делает приложение. – Albert

0

Следите за очень хорошим ответом Tudor, вы также можете посмотреть TPL Dataflow, который обеспечивает очень чистый набор строительных блоков для реализации шаблона производителя-потребителя.

Смежные вопросы