我有一个有很多案例的应用程序。每个案例都有许多多页tif文件。我需要将tf文件转换为pdf文件。由于文件太多,我以为我可以对转换过程进行处理。我目前正在将流程限制为一次十次转换(即十次转换)。当一个转换完成时,另一个转换应该开始。
这是我正在使用的当前设置。
private void ConvertFiles()
{
List<AutoResetEvent> semaphores = new List<AutoResetEvet>();
foreach(String fileName in filesToConvert)
{
String file = fileName;
if(semaphores.Count >= 10)
{
WaitHandle.WaitAny(semaphores.ToArray());
}
AutoResetEvent semaphore = new AutoResetEvent(false);
semaphores.Add(semaphore);
ThreadPool.QueueUserWorkItem(
delegate
{
Convert(file);
semaphore.Set();
semaphores.Remove(semaphore);
}, null);
}
if(semaphores.Count > 0)
{
WaitHandle.WaitAll(semaphores.ToArray());
}
}
使用它,有时会导致异常,说明WaitHandle.WaitAll()或WaitHandle.WaitAny()数组参数的长度不得超过65.我在这种方法中做错了什么,我该如何纠正?< / p>
答案 0 :(得分:1)
看起来你需要删除触发WaitAny函数继续的句柄
if(semaphores.Count >= 10)
{
int index = WaitHandle.WaitAny(semaphores.ToArray());
semaphores.RemoveAt(index);
}
所以基本上我会删除:
semaphores.Remove(semaphore);
从线程调用并使用上面的内容删除已发出信号的事件,看看是否有效。
答案 1 :(得分:1)
您使用的是真正的信号量(System.Threading)吗?使用信号量时,通常会分配最大资源,并且它会自动阻止(当您添加和发布时)。你可以使用WaitAny方法,但我感觉你选择了更难的路线。
答案 2 :(得分:1)
你写的内容有一些问题。
1,它不是线程安全的。您有多个线程添加,删除和等待AutoResetEvents数组。可以在单独的线程上访问List的各个元素,但添加,删除或检查所有元素(如WaitAny调用)的任何内容都需要在锁定内部执行。
第二,无法保证您的代码一次只能处理10个文件。检查List大小的时间与添加新项目的点之间的代码是打开的,以便多个线程通过。
第三,QueueUserWorkItem中启动的线程有可能转换同一个文件。如果不在循环中捕获fileName,转换文件的线程将在执行时使用fileName中的任何值,而不是在调用QueueUserWorkItem时fileName中的任何值。
此代码项目文章应指出您正在尝试执行的操作的正确方向:http://www.codeproject.com/KB/threads/SchedulingEngine.aspx
编辑:
var semaphores = new List<AutoResetEvent>();
foreach (String fileName in filesToConvert)
{
String file = fileName;
AutoResetEvent[] array;
lock (semaphores)
{
array = semaphores.ToArray();
}
if (array.Count() >= 10)
{
WaitHandle.WaitAny(array);
}
var semaphore = new AutoResetEvent(false);
lock (semaphores)
{
semaphores.Add(semaphore);
}
ThreadPool.QueueUserWorkItem(
delegate
{
Convert(file);
lock (semaphores)
{
semaphores.Remove(semaphore);
}
semaphore.Set();
}, null);
}
就我个人而言,我认为我不会这样做......但是,使用你拥有的代码,这应该可行。
答案 3 :(得分:0)
也许你不应该创造这么多的活动?
// input
var filesToConvert = new List<string>();
Action<string> Convert = Console.WriteLine;
// limit
const int MaxThreadsCount = 10;
var fileConverted = new AutoResetEvent(false);
long threadsCount = 0;
// start
foreach (var file in filesToConvert) {
if (threadsCount++ > MaxThreadsCount) // reached max threads count
fileConverted.WaitOne(); // wait for one of started threads
Interlocked.Increment(ref threadsCount);
ThreadPool.QueueUserWorkItem(
delegate {
Convert(file);
Interlocked.Decrement(ref threadsCount);
fileConverted.Set();
});
}
// wait
while (Interlocked.Read(ref threadsCount) > 0) // paranoia?
fileConverted.WaitOne();