There is such a code.
// Коллекция буферов на запись List<List<int>> writeReadyList = new List<List<int>>(); private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Локальный буфер данного потока List<int> localBufer = new List<int>(); Random random = new Random(); while (!backgroundWorker1.CancellationPending) { // Забиваем локальный буфер значениями localBufer.Add(random.Next(0, 100)); if (localBufer.Count > 10) { // Передаем буфер в очередь на запись и обнуляем его writeReadyList.Add(localBufer); localBufer = new List<int>(); } Thread.Sleep(50); } } private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) { while (!backgroundWorker2.CancellationPending) { // Коллекция буферов, которые не удалось записать List<List<int>> failList = new List<List<int>>(); foreach (List<int> currentBufer in writeReadyList) { try { // Пишем значения из перебираемого буфера в базу данных } catch { failList.Add(currentBufer); } } writeReadyList = new List<List<int>>(failList); Thread.Sleep(450); } } A little explanation on the code - the first stream reads some values, saves them in the local buffer. When a certain number of elements are reached, the local buffer is queued for writing and flushed. The second thread looks at what we have in the write queue and, in fact, writes the values to the database. It is impossible to change the collection in foreach, therefore, in order to exclude everything that was recorded successfully, I form a list of unsuccessfully written buffers.
As far as I understand, with this approach several options for incorrect work are possible.
at the time of work foreach in the second stream it will be changed from the first stream - we get an exception?
the second thread iterated through the queue, but has not yet performed the rewrite according to the failed write attempts. At this point, the first one adds the record, but since the second one does not know anything about it, the record will be lost.
How to organize work with the recording queue between these streams? And it is necessary to organize it so that if the second thread is currently processing the queue, then the first thread does not wait for the end of work with the resource, but continues to add the values into its local buffer. Which way to dig?
______UPD:
On the advice of VladD, I used mutexes.
Mutex writeReadyAccess = new Mutex(); private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { if (localBufer.Count > 10) // Таймаут в 1 секунду тк нельзя тормозить первый поток на время обработки очереди if (writeReadyAccess.WaitOne(1)) { // Если второй поток не обрабатывает очередь, то добавляем в нее локальный буфер и обнуляем его writeReadyAccess.ReleaseMutex(); } // Если очередь была в обработке на момент запроса, то продолжаем писать в локальный буфер } private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) { // Этот поток можно тормозить по времени, поэтому ждем без таймаута if (writeReadyAccess.WaitOne()) { // Обработка очереди, в том числе ее перезапись writeReadyAccess.ReleaseMutex(); } }