0

我有一个程序运行多个线程来将 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;
}

我会接受任何来自此代码的建筑批评。

4

2 回答 2

2

multitrheading 的建议方法是使用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.");
    }
}
于 2012-10-11T07:40:33.177 回答
1

我想答案是这取决于。你开始线程了吗,是的。看起来您正在保护共享数据吗?看起来您到处都有复制粘贴的代码。这可以抽象为一个函数,并将上限和下限作为参数。我认为您可以减少这种情况并使用 Parallel.For 或 Parallel.ForEach。最后,我不太记得与 GUI 相关的多线程问题。我看到你在这里使用了一些 GUI。但是您需要确保对标签的更改是由 GUI 线程而不是其他线程进行的。

于 2012-10-11T07:42:59.657 回答