我有了许多情况下的应用程序。每个案例有许多多页TIF文件。我需要将TF文件隐蔽到PDF文件。既然有这么多的文件,我想我可以线程转换过程。我目前限制在一个时间(即10胎面)的过程到十转换。当一个转换完成后,另一个应该开始。

这是当前的设置我使用。

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的长度我是什么在这种方法中做错了,我该如何改正?

有帮助吗?

解决方案

有与您所写的一些问题。

第一,它不是线程安全的。你有多个线程添加,删除和等待AutoResetEvents的阵列上。列表中的单个元素可以在单独的线程访问,但是任何添加,删除或检查的所有元素(如调用了WaitAny),这样做的必要里面的锁。

2,也不能保证你的代码只能同时处理10个文件。其中,增加了新的项目点在列表的大小检查之间的代码,并为您开放,多线程打通。

第三,存在一种用于在QueueUserWorkItem开始转换的相同文件中的线程的潜力。如果没有捕获文件名中的循环内,该线程转换文件将使用什么值是在文件名在执行时,不无论是文件名时,你叫QueueUserWorkItem。

这CodeProject上的文章应该指向你在正确的方向你正在尝试做的事:的 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);
        }

就个人而言,我不认为我会做这种方式......但是,你所拥有的代码工作,这应该工作。

其他提示

您使用一个真正的信号(的System.Threading )?当使用信号灯时,您通常分配你最大的资源,它会自动阻止你(当你添加和释放)。你可以用了WaitAny方法去,但我发现,你所选择的更困难的路线的感觉。

就像您长得需要删除触发了WaitAny功能手柄进行

if(semaphores.Count >= 10)
{
  int index = WaitHandle.WaitAny(semaphores.ToArray());
  semaphores.RemoveAt(index);
}

所以基本上我将消除:

semaphores.Remove(semaphore);

从线程呼叫,并使用上述除去信号通知事件,看看是否能工作。

也许你不应该建立这么多活动?

// 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();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top