我已经和我斗争了好几天,我希望你能把我推向正确的方向。
这是一种递归线程算法,它解析线程中的资源,寻找指向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;
}
}
}
}
}
答案 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;
}
}
}
}
}