C#将状态对象传递给Task更改

时间:2011-04-15 07:28:30

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

我已经和我斗争了好几天,我希望你能把我推向正确的方向。

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

我有一个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)

我的问题是,在主循环中从input传递的状态对象url在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;
        }
      }
    }
  }
}

1 个答案:

答案 0 :(得分: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;
        }
      }
    }
  }
}