Home > Enterprise >  Multithreading error, more than 1 thread in a loop where I expected only 1 at a time?
Multithreading error, more than 1 thread in a loop where I expected only 1 at a time?

Time:06-17

Offending code:

object _objLock = new object();
bool _isCurrentlyUpdatingValues = false;
public void UpdateTestReadValuesTimerCallback(object state)
{
    try
    {
        lock (_objLock)
        {
            if (_isCurrentlyUpdatingValues == true)
            {
                return;
            }

            _isCurrentlyUpdatingValues = true;
        }

        foreach (var prop in CommConfigDnp3.Dnp3Properties)
        {
            if (prop.ReadOrWrite == ReadOrWrite.Read)
            {
                if (prop.PropertyType == PropertyType.Bool)
                {
                    bool? value = CommConfigDnp3.ReadBinary(prop.PropertyName);
                    prop.LastValue = value;
                }
                else
                {
                    double? value = CommConfigDnp3.ReadDouble(prop.PropertyName);
                    prop.LastValue = value;
                }
            }

        }
    }
    finally
    {
        _isCurrentlyUpdatingValues = false;
    }

On breakpoint there is 3 threads into the foreach. I thought it wouldn't be possible. I though that there only could be 1 at the time. What's my bug?

The method is is called on timer each 10 seconds. When I debug the 10 seconds timer timeout happen quickly so many threads calls the method in a debug session but I though only one at a time could reach the foreach loop. Please explain why I have 3 or more? See selected threads in attached image where it shows 3 threads in the foreach (directly in the foreach or somewhere in the callstack of the foreach).

Please note that I know I could have used SpinLock but that is not part of my problem.

enter image description here

CodePudding user response:

Use a local method variable to indicate work can proceed, and only set it to true if the lock is acquired.

try
{
    bool doWork = false;
    lock (_objLock)
    {
        if (!_isCurrentlyUpdatingValues)
        {                     
            _isCurrentlyUpdatingValues = true;
            doWork = true;
        }
    }

    if (doWork)
    {
        // do work here...
        lock (_objLock)
        {                        
            _isCurrentlyUpdatingValues = false;
        }
    }
}
catch
{
    lock (_objLock)
    {
        _isCurrentlyUpdatingValues = false;
    }
    throw;
}
  • Related