简体   繁体   English

如何在c#中使用线程池和互斥锁?

[英]How to use Thread Pool and Mutex in c#?

I try to learn how to use Thread Pool and Mutex, as a practice I'm trying to make an application that copy files from one path in the computer to another path in the computer.我尝试学习如何使用线程池和互斥锁,作为一种练习,我正在尝试制作一个应用程序,将文件从计算机中的一个路径复制到计算机中的另一个路径。 To do this application I used Thread Pool (so a few copies could happen simultaneously):为了做这个应用程序,我使用了线程池(所以几个副本可以同时发生):

object[] paths = new object [2];  // The source path and the destination path
string[] files[] = System.IO.Directory.GetFiles(sourceFolderPath); //string sourceFolderPath = Folder path that contains the files
foreach(string s in files)
{
    paths[0] = s; // The file source - s = the file name with the file path;
    paths[1] = s.Replace(sourceFolderPath, destFolderPath); // Replaces between the source folder and the destination folder but keeps the file name
    ThreadPool.QueueUserWorkItem(new waitCallback(CopyFIle), paths);  
}

So far, the application sends each one of the files to the function that copy the file from the source folder to the destination folder.到目前为止,应用程序将每个文件发送到将文件从源文件夹复制到目标文件夹的函数。

The CopyFile function looks like this: CopyFile 函数如下所示:

static void CopyFiles(object paths)
{
    object[] temp = paths as object[]; // The casting to object array
    string sourcePath = temp[0].ToString();    
    string destPath = temp[1].ToString();
    System.IO.File.Copy(filePath, destPath, true); // The  copy from the source to the dest
}

The weird thing is that when I run the application it throws an exception: "The process cannot access to the file 'C:..........' because it is being used by another process".奇怪的是,当我运行应用程序时,它抛出一个异常:“该进程无法访问文件 'C:.........',因为它正被另一个进程使用”。 When I try to find out the mistake and I run the application step by step the application run properly and the whole files are copied from the source folder to the destination folder.当我试图找出错误并逐步运行应用程序时,应用程序运行正常,并且整个文件都从源文件夹复制到目标文件夹。

That case made me think that maybe the fact that I'm using ThreadPool made a two threads or more to open the same file (the thing that should not happen because I used foreach and each one of the files paths is transferred as a parameter only once).这种情况让我认为,也许我使用 ThreadPool 的事实创建了两个或更多线程来打开同一个文件(这不应该发生,因为我使用了 foreach 并且每个文件路径仅作为参数传输一次)。

To solve this I tried to use Mutex and now the CopyFile function looks like this:为了解决这个问题,我尝试使用 Mutex,现在 CopyFile 函数如下所示:

static Mutex mutex = new Mutex();
static void CopyFiles(object paths)
{
    Mutex.WaitOne();  //Waits until the critical section is free from other threads
    try
    {
         object[] temp = paths as object[]; // The casting to object array
         string sourcePath = temp[0].ToString();    
         string destPath = temp[1].ToString();
         System.IO.File.Copy(filePath, destPath, true); // The  copy from the source to the dest
    }
    Finally
    {
         Mutex.ReleaseMutex(); //Release the critical area
    }
}

Now the application should wait until the critical area is free and just then try to copy the file so the exception: "The process cannot access to the file 'C:..........' because it is being used by another process" should not appear.现在应用程序应该等到关键区域空闲,然后尝试复制文件,因此出现异常:“进程无法访问文件'C:.......',因为它正在被使用由另一个进程”不应该出现。 As I thought, the exception did not appear but the application copied only one file from the source folder to the destination folder and not all of the files.正如我所想,没有出现异常,但应用程序仅将一个文件从源文件夹复制到目标文件夹,而不是所有文件。 When I tried to run this application step by step the same weird thing happened and everything went properly, all of the files were copied to the destination folder.当我尝试逐步运行此应用程序时,发生了同样奇怪的事情并且一切正常,所有文件都被复制到目标文件夹中。

Why this is happen?为什么会这样? And how can I solve this problem so all the files will be copied to the destination folder in a normal application running and not step by step?我该如何解决这个问题,以便在正常运行的应用程序中将所有文件复制到目标文件夹,而不是一步一步地复制?

Your problem isn't the ThreadPool .你的问题不是ThreadPool What goes wrong is the argument.出问题的是争论。

In your first code-snippet, you fill an object-array with two argument-values and pass that to the Queue-method.在您的第一个代码片段中,您使用两个参数值填充对象数组并将其传递给队列方法。 What happens here is, that you use always the same array.这里发生的情况是,您始终使用相同的数组。 So in the first iteration of your foreach -loop, you write two values into the array, pass it.因此,在foreach循环的第一次迭代中,您将两个值写入数组并传递它。 Eventually, the method gets executed be the ThreadPool , using that object-array.最终,该方法被ThreadPool执行,使用该对象数组。 In the same time, in the second iteration of the foreach -loop, you write again into that exact array and pass it again to the ThreadPool .同时,在foreach循环的第二次迭代中,您再次写入该确切数组并将其再次传递给ThreadPool That means, two (or more) Threads are starting to work on that array.这意味着,两个(或更多)线程开始在该数组上工作。

You don't know when the CopyFiles-method is active, so you can't tell when the array was unboxed and is ready for re-usage.您不知道 CopyFiles 方法何时处于活动状态,因此您无法判断阵列何时被拆箱并准备好重新使用。 That could be achieved using a mutual exclusion (the easiest way in C# is using the lock -keyword), but that's not the way you should use here.这可以使用互斥来实现(C# 中最简单的方法是使用lock关键字),但这不是您在这里应该使用的方式。

The better way would be to create new object-arrays each iteration of the foreach -loop.更好的方法是在foreach循环的每次迭代中创建新的对象数组。 Simply change the code to:只需将代码更改为:

string[] files[] = System.IO.Directory.GetFiles(sourceFolderPath); //string sourceFolderPath = Folder path that contains the files
foreach(string s in files)
{
    object[] paths = new object [2];  // The source path and the destination path
    paths[0] = s; // The file source - s = the file name with the file path;
    paths[1] = s.Replace(sourceFolderPath, destFolderPath); // Replaces between the source folder and the destination folder but keeps the file name
    ThreadPool.QueueUserWorkItem(new waitCallback(CopyFIle), paths);  
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM