我有一个程序运行多个线程将pdf文件转换为文件夹及其子目录中的图像。它遍历该文件夹,将所有pdf文件名放在一个列表中,然后使用该列表分割我创建的4个线程之间的工作。现在一切都很完美。正在运行多个线程并将pdf文件同时转换为我指定的不同位置。
我想知道我是否以正确的方式做到了。我访问的几乎每个网站都以不同的方式进行多线程,我不知道哪个是最有效的,最终是正确的。
做一些有用的事情是不行的,如果它做错了我猜...只是为了让我在将来。
我很乐意,如果你能看到这里的代码,看看是否有任何关于多线程运行需要改变的严重错误
static object LockInteger = new object();
static object LockIfCheck = new object();
static object LockInteger = new object();
static object LockIfCheck = new object();
private void button1_Click(object sender, EventArgs e)
{
IterateThrough(txtboxdirectory.Text);
}
public void IterateThrough(string sourceDir)
{
MulThread = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = 0;
int upperbound = (fileList.Count / 4);
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList,sourceDir, dir1);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread.Start();
MulThread1 = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = fileList.Count / 4;
int upperbound = (fileList.Count / 4) * 2;
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList, sourceDir, dir2);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread1.Start();
MulThread2 = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = (fileList.Count / 4) * 2;
int upperbound = (fileList.Count / 4) * 3;
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList, sourceDir, dir3);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread2.Start();
MulThread3 = new Thread(delegate()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int lowerbound = (fileList.Count / 4) * 3;
int upperbound;
if (fileList.Count % 4 != 0)
{
upperbound = ((fileList.Count / 4) * 4) + (fileList.Count % 4) + 1;
}
else
{
upperbound = ((fileList.Count / 4) * 4) + (fileList.Count % 4);
}
for (int i = lowerbound; i < upperbound; i++)
{
forFunction(exceptionFileList, fileList[i], compltetedFileList, sourceDir, dir4);
stopWatch.Stop();
lblFileExecutionTime.BeginInvoke(((Action)(() => lblFileExecutionTime.Text = "Execution Per File " + stopWatch.Elapsed.ToString())));
stopWatch.Reset();
stopWatch.Start();
}
});
MulThread3.Start();
}
然后我锁定了“forFunction”中的一些方法。
private int forFunction(String exceptionFileList, FileInfo z, String compltetedFileList, String sourceDir, String imagedirectory)
{
//heres where it locked up because of this global variable
lock (LockInteger)
{
atPDFNumber++;
}
int blankImage = 1;
int pagesMissing = 0;
//delete the images currently in the folder
deleteCreatedImages(imagedirectory);
//Get the amount of pages in the pdf
int numberPDFPage = numberOfPagesPDF(z.FullName);
//Convert the pdf to images on the users pc
convertToImage(z.FullName, imagedirectory);
//Check the images for blank pages
blankImage = testPixels(imagedirectory, z.FullName);
//Check if the conversion couldnt convert a page because of an error
pagesMissing = numberPDFPage - numberOfFiles;
//int pagesMissing = 0;
//Cancel button is pressed
if (toContinue == 0)
{
return 0;
}
lock (LockIfCheck)
{
//If there is a blank page, or if there is a missing page
if (blankImage == 0 || pagesMissing > 0)
{
myholder = 1;
exceptionFileList += "File Name: " + z.Name + "\r\n"
+ "File Path: " + z.FullName + "\r\n \r\n";
String currentValue = exceptionFileList;
txtboxProblemFiles.BeginInvoke(((Action)(() => txtboxProblemFiles.Text += currentValue.ToString())));
String currentValue3 = z.FullName;
txtboxProblemFiles.BeginInvoke(((Action)(() => listboxProblemFiles.Items.Add(currentValue3))));
}
else
{
compltetedFileList += "Scanning Completed of file: " + "\r\n"
+ "File Name: " + z.Name + "\r\n"
+ "File Path: " + sourceDir + "\r\n \r\n";
}
String currentValue1 = "File Name: " + z.Name + "\r\n";
txtboxCheckedFiles.BeginInvoke(((Action)(() => txtboxCheckedFiles.Text += currentValue1)));
}
myWorkerClass();
return 1;
}
我会接受任何来自此代码的批评。
答案 0 :(得分:2)
建议的多头方式是使用ThreadPool。
ThreadPool的好处在于它管理线程创建,作业分配......并且在更少的资源使用情况下为您提供更好的性能。
来自MSDN的ThreadPool示例:
using System;
using System.Threading;
public class Example {
public static void Main() {
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo) {
// No state object was passed to QueueUserWorkItem, so
// stateInfo is null.
Console.WriteLine("Hello from the thread pool.");
}
}
答案 1 :(得分:1)
我想答案是肯定的。你是在开始线程吗?您是否正在保护共享数据?看起来你到处都有复制粘贴的代码。这可以被抽象为一个函数,上下界成为参数。我想你可以减少它并使用Parallel.For或Parallel.ForEach。最后,我不记得与GUI有关的多线程问题。我看到你在这里使用了一些GUI。但是你需要确保标签的更改是由GUI线程而不是其他线程完成的。