跟踪多线程应用程序中的任务编号

时间:2012-08-27 16:13:49

标签: c# multithreading

我正在编写一个多线程应用程序,其中一部分代码必须是线程安全的,以便跟踪任务编号。

我有这个方法:

private void IncrementTaskNumber() {
   Interlocked.Increment(ref _TaskNumber);
}

_TaskNumber是同一个类中的私有int。问题是,这会抛出一个“属性,索引器或动态成员访问可能不会作为out或ref参数传递”异常。 为了解决这个问题,我做了:

private void IncrementTaskNumber() {
   int _taskNum = _TaskNumber;
   Interlocked.Increment(ref _taskNum);
   _TaskNumber = _taskNum;
}

这仍然是线程安全吗?

3 个答案:

答案 0 :(得分:3)

  

_TaskNumber是同一个类中的私有int。

_TaskNumber必须是私有字段才能实现此目的。您可能将其作为私人财产。

将其定义为:

private int _TaskNumber;

它会起作用。

另请注意,您当前的解决方法会引入竞争条件 - 您可以通过使用临时变量来有效地消除原子增量,这首先会破坏使用Interlocked的目的。您需要直接增加字段。

答案 1 :(得分:1)

IncrementTaskNumber方法似乎没有锁定机制。除非你只从一个地方打电话,否则它不是线程安全的。您想要做的第一个实现,即使它可以工作也不会,因为Interlocked.Increment(ref _TaskNumber);可能在第一次执行之前第二次被调用,并且写入ref参数。

编辑: 如果你想让它成为线程安全的,你可以像这样修改yoru方法:

private void IncrementTaskNumber()
{
    lock (_TaskNumber)
        _TaskNumber++;
}

编辑2 :(如果使用lock对您的应用程序来说过于昂贵,您可能需要查看其他解决方案。)

答案 2 :(得分:0)

这绝对不是线程安全的:

private void IncrementTaskNumber() {
   int _taskNum = _TaskNumber;
   Interlocked.Increment(ref _taskNum);
   _TaskNumber = _taskNum;
}

因为执行序列的线程可能在这3个操作中的每个操作之间被中断。除非你引入一个循环,如果在此期间本地值发生变化,仍会继续重试,但这将无效,但这基本上意味着你要使用Interlocked.Increment重新实现Interlocked.Increment。 :)

只需将_TaskNumber设为成员变量,而不是属性。