Search code examples
c#listconcurrencynaudio

Safely clear List (with concurrency)


Good day! I have List<byte> soundBuffer - to get audio signal from microphone.

void _waveInStream_DataAvailable(object sender, WaveInEventArgs e)
{
  lock(_lockObject)
   {
    for (int i = 0; i < e.BytesRecorded; i++)
            {
                _soundBuffer.Add(e.Buffer[i]);
            }
   }
}

And if user waits a long type- buffer will be very big (2 mb per minute). So, i create a timer:

 _timerSoundCount = new System.Timers.Timer();
 _timerSoundCount.Interval = 10000;  // check every 10 second
 _timerSoundCount.Enabled = true;
 _timerSoundCount.Elapsed += _timerSoundCount_Elapsed;
 _timerSoundCount.Start();

And:

void _timerSoundCount_Elapsed(object sender, ElapsedEventArgs e)
    {
        if(_soundBuffer.Count>2*1024*1024)
       {
        var energy = GetSignalEnergy(_soundBuffer);
        if(energy<1) //if energy of signal is small- clear buffer.
        {
            lock (_lockObject)
                _soundBuffer.Clear();
        }
        }
        else if(_soundBuffer.Count>=5*1024*1024)
         {... the same operation}
        else if(_sounfBuffer.Count>=10*1024*1024)
         { _soundBuffer.Clear();//very big buffer }
    }

Every 10 seconds i check the buffer size. If it is too big- i just clear buffer, because i can detect Speech\Silence and clear buffer at that code.

So, point is: can it be that when i execute _soundBuffer.Clear() at timer and at the same time at _waveInStream_DataAvailable i will add new bytes to buffer- can it be currupt write? Can it be a deadlock?

If so, can you help me how to safetely clear buffer?

Thank you!


Solution

  • If the two actions are being undertaken from the same thread, there is no chance of a deadlock occurring.

    If there are multiple threads writing/reading the list at the same time, then lock should be used (https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx) to prevent multiple threads accessing the object simultaneously. See here (use the same lock object at two different code block?) for a simple example.

    Alternatively, you can use a concurrent collection from the System.Collections.Concurrent namespace (https://msdn.microsoft.com/en-us/library/system.collections.concurrent(v=vs.110).aspx) Perhaps a ConcurrentQueue would be appropriate if the data is not being randomly accessed. You can also implement your own concurrent collection, although this is much more complex.