信号量和多线程Process.Start的问题

时间:2012-11-09 16:05:21

标签: c# multithreading semaphore

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

    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 个答案:

答案 0 :(得分:0)

  1. 无法保证线程实际启动的顺序。很可能两个线程(在Thread.Start()意义上)相互快速连续启动可能会遇到“第二个”实际上在“第一个”之前开始执行的线程。如果有序执行很重要,则需要序列化它们的执行(这似乎不需要启动多个线程。)

  2. 如果您确定所有进程都使用正确的输入文件名启动,我很好奇。您的委托使用情况对我来说就像您实际上最终会得到两个启动相同的文件,我想知道这是否有助于您的第二个问题。

  3. 多久一次?你的电脑目前还在做什么吗?您收到任何消息,BSOD或任何形式的信息吗?无论如何,这是不正常的。

答案 1 :(得分: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,您还可以拥有独立的进度条等。

代码未经测试。