我在c#中以正确的方式进行多线程处理吗?

时间:2012-10-11 07:22:13

标签: c# multithreading

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

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

2 个答案:

答案 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线程而不是其他线程完成的。