Search code examples
c#lockinginterlocked-increment

Programming without locks using Interlocked class


I need to dispose of locks in my C# application using Interlocked class. I have such code:

class LogStruct
{
    public Dictionary<string, ulong> domainName;
    public Dictionary<string, ulong> URL;
    public Dictionary<string, ulong> domainData;
    public Dictionary<string, ulong> errorCodes;

    public LogStruct()
    {
        domainName = new Dictionary<string, ulong> { };
        URL = new Dictionary<string, ulong> { };
        domainData = new Dictionary<string, ulong> { };
        errorCodes = new Dictionary<string, ulong> { };
    }
}

class CLogParser
{
    string domainName = parameters[0];
    string errorCode = matches[1].Value;
    LogStruct m_logStruct;
    ...
    public CLogParser()
    {
         m_logStruct = new LogStruct();
    }
    ...
    public void ThreadProc(object param)
    {
      if (m_logStruct.errorCodes.ContainsKey(fullErrCode))
      {
        lock (m_logStruct.errorCodes)
        {
          m_logStruct.errorCodes[fullErrCode]++;
        }
      }
    }
}

And when I want to replace the lock in ThreadProc on Interlocked class, for example:

public void ThreadProc(object param)
{
  if (m_logStruct.errorCodes.ContainsKey(fullErrCode))
  {
    Interlocked.Increment(m_logStruct.errorCodes[fullErrCode]);
  }
}

I get this error:

Error CS1502: The best overloaded method match for 
`System.Threading.Interlocked.Increment(ref int)' 
has some invalid arguments (CS1502) (projectx)

and this error: Error CS1503: Argument #1' cannot convert ulong to ref int' (CS1503) (projectx)

How to fix it?


Solution

  • You need to use ref when calling Interlocked.Increment, e.g.

    Interlocked.Increment(ref myLong);
    

    or in your case

    Interlocked.Increment(ref m_logStruct.errorCodes[fullErrCode]);
    

    It is important to realize that Interlocked.Increment(ref long) is...

    truly atomic only on systems where a System.IntPtr is 64 bits long. On other systems, these methods are atomic with respect to each other, but not with respect to other means of accessing the data. Thus, to be thread safe on 32-bit systems, any access to a 64-bit value must be made through the members of the Interlocked class.

    http://msdn.microsoft.com/en-us/library/zs86dyzy(v=vs.110).aspx

    On a side note, the actual performance difference between

    Interlocked.Increment(ref m_logStruct.errorCodes[fullErrCode]);
    

    and

    lock(myLock)
    {
        m_logStruct.errorCodes[fullErrCode]++;
    }
    

    will be trivial and unimportant for most applications.

    UPDATE

    It looks like your data type is unsigned. Have a look at Jon Skeet's solution for using Interlocked.Increment with unsigned types:

    https://stackoverflow.com/a/934677/141172