c# - 多线程增量并在没有锁的情况下跳过0?

标签 c# .net multithreading atomic

我有一个 ushort 计数器(偶尔会翻转)。使用这个值的消息传递协议(protocol)不允许 0。我需要一些线程安全的方法来增加这个计数器(存储在类字段中)每次读取它,如果我将它存储为 int 并使用互锁。增量。但是,我不确定如何将跳过 0 合并到其中。偶尔跳过几个数字也没关系;我的输出序列不一定是完美的。我不能在任何 4000 block 中重复使用相同的数字。我想避免使用锁。

最佳答案

这个:

给定:

static int value = ushort.MaxValue;

在代码中:

int temp, temp2;

do
{
    temp = value;
    temp2 = temp == ushort.MaxValue ? 1 : temp + 1;
}
while (Interlocked.CompareExchange(ref value, temp2, temp) != temp);

你必须使用 int 然后转换它(例如在 get 属性中),因为 Interlocked 不是t 用于所有基本类型。

我们可能会在像这样的高度线程化的上下文中让它更快一些:

int temp = value;

while (true)
{
    int temp2 = temp == ushort.MaxValue ? 1 : temp + 1;

    int temp3 = Interlocked.CompareExchange(ref value, temp2, temp);

    if (temp3 == temp)
    {
        break;
    }

    temp = temp3;
}

这样我们就可以少读一次失败了。

正如我在评论中所写,这段代码的中心思想是增加一个临时变量 (temp2) 计数器,然后尝试将我们知道的旧值与新值 (Interlocked.CompareExchange)。如果没有人触及中间的旧值 (Interlocked.CompareExchange() == temp),那么我们就完成了。如果其他人增加了值(value),那么我们再做一次尝试。 ushort 是通过使用具有固定最大值的 int 来模拟的 (temp == ushort.MaxValue ? 1 : temp + 1) .

第二个版本,在 Interlocked.CompareExchange() 失败时重新使用函数读取的值作为加 1 的新基础。

以这种方式使用的 Interlocked.CompareExchange 可以用作构建其他 Interlocked 操作的基础(您需要一个 Interlocked.Multiply ? 你做一个“标准”乘法,然后尝试 Interlocked.CompareExchange 旧值)

关于c# - 多线程增量并在没有锁的情况下跳过0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18600181/

相关文章:

C# 自定义组合框排序

c# - 抽象类的子类,总是调用抽象构造函数

c# - 需要帮助了解 Ninject 如何将 Nhibernate SessionFactory 实例放入 UnitOfWork 中?

.net - 隔离的 Azure 函数 Dockerfile

c# - 在构造函数中向RichTextBox添加文本

c# - 有没有一种方法可以根据特定规则自动重新发送 Outlook 2007 和 MS Exchange 的电子邮件?

c# - 错误 : Could not load file or assembly 'Microsoft.Win32Registry' from . .NET Framework 控制台应用程序使用的 NET 标准库

ruby - Ruby检查线程是否为 “free”

java - 结束线程的执行而不使用其 stop() 方法

java - 调用notify并不会唤醒其他等待线程