1

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?

pragmus
  • 3,513
  • 3
  • 24
  • 46
  • 1
    Add "ref" to the call site. (Which is not to say, by the way, that the rest of your approach is assured of succeeding...lock-free code is frequently very difficult to get right, even by the experts). – Peter Duniho Oct 16 '14 at 22:03
  • @PeterDuniho, it doesn't help – pragmus Oct 16 '14 at 22:04
  • 1
    Ah...I see. You're using "ulong". You can only use signed ints with Interlocked.Increment, not unsigned. – Peter Duniho Oct 16 '14 at 22:05

1 Answers1

2

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

Community
  • 1
  • 1
Eric J.
  • 147,927
  • 63
  • 340
  • 553