2014-04-10 85 views
0

我有一个线程池,所有线程都有一组固定的图像。假设他们有100张图片。我需要检测哪个图像包含驻留在图像库中的另一个图像。多线程读取随机文件

  • 线程1 - 100图像

  • 线程2 - 100图像

  • 线3 - 100图像

  • 螺纹4 - 100图像

  • 图像库 - 50张图片

现在我需要所有线程来查看图像库内部,以查看它们所持有的某个图像是否与图像库相似。我有我的图像匹配完成,我担心的是如果多个线程可能会打开相同的图像文件。解决这个问题的正确方法是什么?不要为每个IO“锁定”所有其他线程。

谢谢!

+1

如果阅读这些图像的唯一操作,你不应该有并发问题(假设一旦线程开始处理,没有其他人更改图像) –

+0

您可以使用[Semaphore](http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx)限制可以同时访问图像的线程数量。同样,您可以使用[Mutex](http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx)来确保一次只有一个线程可以访问这些图像。 – Icemanind

+0

我不明白。首先你会说:'所有的线程都有一组固定的图像',但后来你告诉我们:'多个线程可能会打开同一个图像文件'......做还是没有固定的图像集? –

回答

-1

假设所有的线程都在同一组,他们必须努力上的图像,并假设pahts这些文件在列表中或某些其他集合,你可以尝试这样的事:

// A shared collection 
List<string> paths = new List<string>(); 
// Fill this collection with your fixed set. 

IEnumerator<T> e = paths.GetEnumerator(); 
// Now create all threads and use e as the parameter. Now all threads have the same enumerator. 

// Inside each thread you can do this: 
while(true) 
{  
    string path; 
    lock(e) 
    { 
     if (!e.MoveNext()) 
      return; // Exit the thread. 
     path = e.Current; 
    } 
    // From here, open the file, read the image, process it, etc. 
} 

在这个例子你只能对枚举器加锁。只有一个线程可以同时读取它。所以每次调用时都会有不同的路径。

锁定外,你可以做所有的处理,I/O等

当然藏品中还可以是另一种类型的,像一个数组。

+0

你的假设是正确的。我想我可能已经解释了一些错误。每个图像必须检查底座中的所有图像。我认为你实施它的方式,它只检查一次基地?由于e.MoveNext()将返回一个不同的路径,因此每个线程都必须获取他们拥有的每个图像,然后再检查它们是否是整个基地。 –

+0

所以......要清楚:你需要一个包含50个图像的集合,您需要与4x100图像进行比较。因此总共需要做50x400 = 20,000比较操作。这50个图像是共享的,这100个图像对于每个线程都是唯一的? –

+0

这正是我需要做的。 –

0

这样的事情呢,每个线程都有一个对图像库的引用,并提供一个代表图像库中每个文件的代理。这是图像库可能看起来像什么的骨架。

public class ImageBank { 
    public delegate bool ImageProcessorDelegate(String imageName); 

    private readonly List<String> _imageBank; 

    public ImageBank() 
    { 
     // initialize _imageBank with list of image file names 
    } 

    private int ImageBankCount { 
     get { 
      lock(_imageBank) { 
       return _imageBank.Count; 
      } 
     } 
    } 

    private List<String> FilterImageBank(ISet<String> exclude) 
    { 
     lock(_imageBank) 
     { 
      return _imageBank.Where(name => !exclude.Contains(name)).ToList(); 
     } 
    } 

    public void ProcessImages(ImageProcessorDelegate imageProcessor) 
    { 
     var continueProcessing = true; 
     var processedImages = new HashSet<String>(); 
     var remainingImages = new List<String>(); 

     do 
     { 
      remainingImages = FilterImageBank(processedImages); 

      while(continueProcessing && remainingImages.Any()) 
      { 
       var currentImageName = remainingImages[0]; 
       remainingImages.RemoveAt(0); 

       // protect this image being accessed by multiple threads. 
       var mutex = new Mutex(false, currentImageName);    
       if (mutex.WaitOne(0)) 
       { 
        try 
        { 
         // break out of loop of the processor found what it was looking for. 
         continueProcessing = imageProcessor(currentImageName); 
        } 
        catch (Exception) 
        { 
         // exception thrown by the imageProcessor... do something about it. 
        } 
        finally 
        { 
         // add the current name to the set of images we've alread seen and reset the mutex we acquired 
         processedImages.Add(currentImageName); 
         mutex.ReleaseMutex(); 
        } 
       } 
      } 
     } 
     while(continueProcessing); 
    } 
} 

然后,每个线程将有其图像(_myImageList)列表和ThreadProc看起来是这样的:

void ThreadProc(object bank) 
{ 
    var imageBank = bank as ImageBank; 
    foreach(var myImage in _myImageList) 
    { 
    imageBank.ProcessImages(imageName => 
     { 
     // do something with imageName and myImage 
     // return true to continue with the next image from the image bank 
     // or false to stop processing more images from the image bank 
     } 
    ); 
    } 
}