【问题标题】:Keeping track of task number in multi threaded application跟踪多线程应用程序中的任务编号
【发布时间】:2012-08-27 16:13:49
【问题描述】:

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

我有这个方法:

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

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

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

这仍然是线程安全的吗?

【问题讨论】:

  • 请显示_TaskNumber的声明。鉴于错误消息,听起来它被定义为 private int _TaskNumber { get; set; } 之类的东西 - 对吗?
  • @Reed Copsey,是的,私人 int _TaskNumber {get;设置;}
  • 您需要使用字段,而不是私有属性 - 详情请参阅我的回答。

标签: c# multithreading


【解决方案1】:

_TaskNumber 是同一类中的私有 int。

_TaskNumber 必须是一个私有的字段 才能工作。您可能将其作为私有财产。

定义为:

private int _TaskNumber;

它会起作用的。

还请注意,您当前的解决方法引入了竞争条件 - 您通过使用临时变量有效地摆脱了原子增量,这首先违背了使用 Interlocked 的目的。您需要直接增加该字段。

【讨论】:

  • 非常感谢。这比预期的要容易:)
【解决方案2】:

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

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

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

编辑 2:(如果使用 lock 对您的应用程序来说成本太高,您可能需要研究其他解决方案。)

【讨论】:

  • 如果使用锁为每个任务执行一个增量太昂贵,您可能会遇到更大的问题。
  • @Servy 对于小型工作机构,锁可能变得非常昂贵。 TPL 中有大量的管道来避免因为这个原因而不得不锁定......
  • @ReedCopsey 如果这是需要在循环中经常完成的事情,那么我同意,但由于如果这是一个真正的问题,每个任务只执行一次,那么这可能意味着你也有许多任务完成的工作单元太小。
  • @Servy True - 这取决于“任务”的组成部分
  • 如果您启动/处理足够多的线程以使锁成为瓶颈,那就是问题所在。我建议锁定解决方案考虑到它是在这种情况下完成的。
【解决方案3】:

这绝对不是线程安全的:

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

因为执行序列的线程可能在这 3 个操作之间被中断。这将不起作用,除非您引入一个循环,如果同时本地值发生更改,该循环会不断重试递增,但这基本上意味着您正在使用Interlocked.Increment 重新实现Interlocked.Increment。 :)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 2021-12-31
    • 2010-11-03
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多