【问题标题】:C# Passed state object to Task gets changedC# 传递给 Task 的状态对象被改变
【发布时间】:2011-04-15 07:28:29
【问题描述】:

我为此奋斗了好几天,希望你能把我推向正确的方向。

这是一种递归线程算法,它解析线程中的资源,寻找指向其他资源的链接,将它们存储在ConcurrentBag 中以供将来取出。线程创建受限于可配置大小的数组以保留资源。

我有一个private static ConcurrentBag<string>,它被许多线程填充。这些Tasks 存储在private static Task[] 中,具有可配置的大小(应用首选项)。
Main 中有一个循环将 TryTake() 转换为本地 string url 变量。当成功时,它循环 Task[] 试图找到空槽创建新的 Task 传递状态对象 url 并将其存储在 Task[] 中,如下所示:

TaskArray[x] = new Task(FindLinks, url, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);

FindLinks 被声明为

private static readonly Action<object> FindLinks = input => { ... }

在主Task[] 循环中,我将url 设置为null,然后再下一个TryTake(out url)

我的问题是从主循环中的url 传递的状态对象input 在Task lambda 函数中变成null。我已经阅读了几乎所有关于 TPL 的 MSDN 文章,但无法弄清楚这一点:(

如何在不关闭(或发生任何情况)的情况下安全地将变量(字符串)传递给Task

也欢迎任何其他关于改进此算法的想法。

谢谢。

编辑:
我通过重新排序语句和稍微重写主循环中的代码解决了这个问题。不再将 null 分配给变量。我怀疑这是由编译器的语句重新排序或抢占引起的。这是它现在的样子,不会再造成麻烦了:

string url;
if (CollectedLinks.TryTake(out url))
{
  var queued = false;
  while (!queued)
  {
    // Loops thru the array looking for empty slot (null)
    for (byte i = 0; i < TaskArray.Length; i++)
    {
      if (TaskArray[i] == null)
      {
        TaskArray[i] = new Task(FindLinks, url, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
        TaskArray[i].Start(TaskScheduler.Current);
        queued = true; break;
      }
    }

    if (!queued)
    {
      // Loop and clean the array
      for (var i = 0; i < TaskArray.Length; i++)
      {
        if (TaskArray[i] == null)
          continue;
        if (TaskArray[i].Status == TaskStatus.RanToCompletion || TaskArray[i].Status == TaskStatus.Canceled || TaskArray[i].Status == TaskStatus.Faulted)
        {
          TaskArray[i].Wait(0);
          TaskArray[i] = null;
        }
      }
    }
  }
}

【问题讨论】:

  • 您已经描述了很多代码,但如果您能真正显示这些代码,那就更清楚了。很难理解正在发生的事情。特别是,答案很容易取决于您是否捕获了任何变量。
  • 我明白了。不幸的是,代码是如此复杂和重构,以至于我需要一些时间来收集所有必要的部分并过滤掉其余部分,并且您可能需要同样的时间才能在脑海中将它们链接在一起。不过,我会尽快做到最好。
  • 如果您已经解决了问题,看起来您已经解决了,您应该将解决方案发布为答案并将其标记为已回答。这将让其他人更快地知道问题已经解决。

标签: c# multithreading task task-parallel-library


【解决方案1】:

我通过重新排序语句和稍微重写主循环中的代码解决了这个问题。不再将 null 分配给变量。我怀疑这是由编译器的语句重新排序或抢占引起的。这是它现在的样子,不会再造成麻烦了:

string url;
if (CollectedLinks.TryTake(out url))
{
  var queued = false;
  while (!queued)
  {
    // Loops thru the array looking for empty slot (null)
    for (byte i = 0; i < TaskArray.Length; i++)
    {
      if (TaskArray[i] == null)
      {
        TaskArray[i] = new Task(FindLinks, url, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
        TaskArray[i].Start(TaskScheduler.Current);
        queued = true; break;
      }
    }

    if (!queued)
    {
      // Loop and clean the array
      for (var i = 0; i < TaskArray.Length; i++)
      {
        if (TaskArray[i] == null)
          continue;
        if (TaskArray[i].Status == TaskStatus.RanToCompletion || TaskArray[i].Status == TaskStatus.Canceled || TaskArray[i].Status == TaskStatus.Faulted)
        {
          TaskArray[i].Wait(0);
          TaskArray[i] = null;
        }
      }
    }
  }
}

【讨论】:

    猜你喜欢
    • 2018-11-24
    • 2019-06-25
    • 2019-10-27
    • 2018-07-28
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-29
    相关资源
    最近更新 更多