【问题标题】:Programming without locks using Interlocked class使用 Interlocked 类进行无锁编程
【发布时间】:2014-12-12 10:09:50
【问题描述】:

我需要使用 Interlocked 类处理我的 C# 应用程序中的锁。我有这样的代码:

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]++;
        }
      }
    }
}

而当我想在Interlocked类上替换ThreadProc中的锁时,例如:

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

我收到此错误:

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

这个错误: 错误 CS1503:参数 #1' cannot convert ulong 到 ref int' (CS1503) (projectx)

如何解决?

【问题讨论】:

  • 将“ref”添加到调用站点。 (顺便说一句,这并不是说你的方法的其余部分一定会成功......无锁代码通常很难正确,即使是专家也是如此)。
  • @PeterDuniho,它没有帮助
  • 啊...我明白了。您正在使用“ulong”。您只能将带符号的整数与 Interlocked.Increment 一起使用,而不是无符号的。

标签: c# locking interlocked-increment


【解决方案1】:

调用Interlocked.Increment时需要使用ref,例如

Interlocked.Increment(ref myLong);

或者在你的情况下

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

重要的是要意识到Interlocked.Increment(ref long) 是......

只有在 System.IntPtr 为 64 位长的系统上才是真正的原子。在其他系统上,这些方法相对于彼此是原子的,但相对于其他访问数据的方式而言不是原子的。因此,要在 32 位系统上实现线程安全,对 64 位值的任何访问都必须通过 Interlocked 类的成员进行。

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

顺便说一下,两者之间的实际性能差异

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

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

对于大多数应用程序来说都是微不足道且不重要的。

更新

看起来您的数据类型是无符号的。看看 Jon Skeet 使用无符号类型的 Interlocked.Increment 的解决方案:

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

【讨论】:

    猜你喜欢
    • 2014-07-13
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多