2

不确定我下面的代码有什么问题,但没有按预期工作。设计是允许用户从 ListBox 中选择任意数量的输入文件,然后单击“执行”按钮以使用不同的输入文件启动相同的可执行文件。我将添加一个控件以允许用户指定并发进程的数量,但现在我将硬编码为 3 以进行测试。我的期望是每个可执行文件都将按顺序开始(尽管我知道它们可能不会以这种方式完成)并且一次只会执行 3 个(尽管这个数字最终将由用户输入控件控制)。我想为调用进程的函数增加额外的功能,即任务优先级,返回退出代码,但现在我无法让基本功能正常工作。我尝试了许多代码变体 已在此站点和网络上的其他站点上找到,但仍无法使其正常工作。这是当前版本:

    private void btnParserExe_Click(object sender, EventArgs e)
    {
        Pool = new Semaphore(3,3);  //Pool above declared as class variable 
        string ExeName = "C:\\Program Files (x86)\\Norman\\bin\\OC2.exe";
        string Args;
        string ArgDir = this.dirListBox1.Path + "\\";

        for (int i = 0; i < this.fileListBox1.Items.Count; i++)
        {
            if (this.fileListBox1.GetSelected(i) == true)
            {
                Args = "-i " + this.fileListBox1.get_Items(i) + " -r -c -noerr";
                Thread thread = new Thread(() => DoWork(ArgDir, ExeName, Args, "3"));
                thread.Start();
            }
        }
    }


    private static void DoWork(string WorkingDir, string exefile, string parameters, string priority)
    {
        Pool.WaitOne();

        Process exeProcess = new Process();
        int exitCode;

        try
        {
            exeProcess.StartInfo.FileName = exefile;
            exeProcess.StartInfo.Arguments = parameters;
            exeProcess.StartInfo.WorkingDirectory = WorkingDir;
            exeProcess.Start();
            exeProcess.WaitForExit();
        }
        catch (Exception ex)
        {
            MessageBox.Show("ERROR EXECUTING: " + parameters + " " + ex.Message);
        }
        finally
        {
            exitCode = exeProcess.ExitCode;
        }
        Pool.Release();
    }

}

我遇到的三个主要问题:

  1. 作业并不总是以正确的顺序开始(ListBox 中较低的某些项目在较高的其他项目之前启动)
  2. 有时启动的过程似乎停止了,好像它已经完成但窗口仍然在屏幕上。这是一个非常一致的问题,但并不总是相同的任务/输入文件会停止。有时,在先前的测试中运行良好的会停止运行,反之亦然。
  3. 我的笔记本电脑在测试这部分代码时重新启动??

任何反馈、链接、示例将不胜感激。

4

2 回答 2

0
  1. 无法保证线程实际启动的顺序。很有可能两个线程(在Thread.Start()某种意义上)彼此快速连续启动,可能会经历“第二个”线程实际上在“第一个”之前开始执行。如果有序执行很重要,您将需要序列化它们的执行(这似乎消除了启动多个线程的需要。)

  2. 我很好奇您是否确定所有进程都以正确的输入文件名启动。在我看来,您的委托使用情况实际上可能会以两个启动同一个文件而告终,我想知道这是否会导致您的第二个问题。

  3. 多常?您的计算机此时是否在执行其他操作?您是否收到任何消息、蓝屏死机或任何形式的信息?这无论如何都不正常。

于 2012-11-09T16:23:10.640 回答
0

.Net 4.0 现在为简单的并行任务提供了一些新工具:http: //msdn.microsoft.com/en-us/library/dd987838 (v=vs.100).aspx

    string ExeName = "C:\\Program Files (x86)\\Norman\\bin\\OC2.exe";
    string Args;
    string ArgDir = "\\";

    //Simulated listbox items here:
    string[] filelist = new string[] {"file1", "file2"};

    System.Threading.Tasks.ParallelOptions options = new System.Threading.Tasks.ParallelOptions();
    options.MaxDegreeOfParallelism = 3;
    System.Threading.Tasks.Parallel.For(0, 10, options, (i => {

        Args = "-i " + filelist[i] + " -r -c -noerr";
        DoWork(ArgDir, ExeName, Args, "3");
    }
        ));
}

通过使用 Parallel.For,您可以管理并发,并且任务应该按顺序启动。

在 .Net 2.0 中,您可以使用一些 BackgroundWorkers 和一个简单的控制器方法。就像是:

Stack<string> filelist = new Stack<string>() {"file1", "file2"};

private void Setup()
{

    System.ComponentModel.BackgroundWorker backgroundWorker1;
    System.ComponentModel.BackgroundWorker backgroundWorker2;

    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);

    backgroundWorker2.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
    backgroundWorker2.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
}

private void Execute()
{
    backgroundWorker1.DoWork();
    backgroundWorker2.DoWork();
}

private string GetNextItem()
{
    //this is a crude controller
    return filelist.Pop();
}

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{   
    // Get the BackgroundWorker that raised this event.
    BackgroundWorker worker = sender as BackgroundWorker;
    string nextFile = GetNextItem();
    //Some simple check here to see if there were any items left or quit
    ....
    //Now do work
    Args = "-i " + nextFile  + " -r -c -noerr";
    DoWork(ArgDir, ExeName, Args, "3");

}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{   
    // Check for errors...
    ...

    // See if more work to do
    if (filelist.Count > 0)
    {
        //Repeat task
        BackgroundWorker worker = sender as BackgroundWorker;
        worker.DoWork();
    }
}

使用 BackgroundWorkers,您还可以拥有独立的进度条等。

代码未经测试。

于 2012-11-09T17:24:11.213 回答