C# 进程的信号量和多线程问题。启动

C# 进程的信号量和多线程问题。启动,c#,multithreading,semaphore,C#,Multithreading,Semaphore,我不确定下面的代码有什么问题,但没有按预期工作。该设计允许用户从列表框中选择任意数量的输入文件,然后单击“执行”按钮,使用不同的输入文件启动相同的可执行文件。我将添加一个控件,允许用户指定并发进程的数量,但现在我将硬编码为3以进行测试。我的期望是每个可执行文件都将按顺序启动(尽管我知道它们可能不会以这种方式完成),并且一次只执行3个(尽管这个数字最终将由用户输入控件控制)。我希望在调用流程的函数中添加其他功能,即任务优先级、返回exitcode,但目前我无法使基本功能正常工作。我在这个网站和其他

我不确定下面的代码有什么问题,但没有按预期工作。该设计允许用户从列表框中选择任意数量的输入文件,然后单击“执行”按钮,使用不同的输入文件启动相同的可执行文件。我将添加一个控件,允许用户指定并发进程的数量,但现在我将硬编码为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();
    }

}
private void btnparserex\u单击(对象发送方,事件参数)
{
Pool=新信号量(3,3);//上面的Pool声明为类变量
string ExeName=“C:\\Program Files(x86)\\Norman\\bin\\OC2.exe”;
字符串参数;
字符串ArgDir=this.dirListBox1.Path+“\\”;
for(int i=0;iDoWork(ArgDir,ExeName,Args,“3”);
thread.Start();
}
}
}
私有静态void DoWork(字符串WorkingDir、字符串exefile、字符串参数、字符串优先级)
{
Pool.WaitOne();
进程exeProcess=新进程();
int exitCode;
尝试
{
exeProcess.StartInfo.FileName=exefile;
exeProcess.StartInfo.Arguments=参数;
exeProcess.StartInfo.WorkingDirectory=WorkingDir;
exeProcess.Start();
exeProcess.WaitForExit();
}
捕获(例外情况除外)
{
MessageBox.Show(“执行错误:“+parameters+”“+ex.Message”);
}
最后
{
exitCode=execprocess.exitCode;
}
Pool.Release();
}
}
我面临的三个主要问题:

  • 作业并非总是以正确的顺序启动(列表框中较低的某些项在较高的其他项之前启动)
  • 有时启动的过程似乎会暂停,好像它已完成,但窗口仍保留在屏幕上。这是一个相当一致的问题,但并不总是相同的任务/输入文件会暂停。有时,在先前的测试中表现良好的测试将暂停,反之亦然
  • 我的笔记本电脑在测试这部分代码时重新启动
  • 任何反馈、链接、示例都将不胜感激

  • 对于线程实际启动的顺序没有任何保证。很可能两个线程(在
    Thread.Start()
    sense中)快速连续启动时,可能会经历“第二个”线程,而实际上是在“第一个”线程之前开始执行。如果有序执行很重要,则需要序列化它们的执行(这似乎可以避免启动多个线程的需要)

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

  • 多久一次?您的计算机此时是否正在执行其他操作?您是否收到任何消息、BSOD或任何形式的信息?这无论如何都是不正常的


  • .Net 4.0现在为简单的并行任务提供了一些新工具:

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

    在.NET2.0中,您可以使用一些后台工作人员和一个简单的控制器方法。比如:

    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();
        }
    }
    
    Stack filelist=newstack(){“file1”、“file2”};
    私有无效设置()
    {
    System.ComponentModel.BackgroundWorker backgroundWorker1;
    System.ComponentModel.BackgroundWorker BackgroundWorker 2;
    backgroundWorker1.DoWork+=新的DoworkerVenthandler(backgroundWorker_DoWork);
    backgroundWorker1.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(backgroundWorker\u RunWorkerCompleted);
    backgroundWorker2.DoWork+=新的DoworkerVenthandler(backgroundWorker_DoWork);
    backgroundWorker2.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(backgroundWorker\u RunWorkerCompleted);
    }
    私有void Execute()
    {
    backgroundWorker1.dowwork();
    backgroundWorker2.DoWork();
    }
    私有字符串GetNextItem()
    {
    //这是一个粗糙的控制器
    返回filelist.Pop();
    }
    私有void backgroundWorker_DoWork(对象发送方,DoWorkEventArgs e)
    {   
    //获取引发此事件的BackgroundWorker。
    BackgroundWorker worker=发件人作为BackgroundWorker;
    字符串nextFile=GetNextItem();
    //在这里进行一些简单的检查,看看是否有任何项目剩余或退出
    ....
    //现在开始工作
    Args=“-i”+nextFile+”-r-c-noerr”;
    DoWork(ArgDir,ExeName,Args,“3”);
    }
    私有void backgroundWorker_RunWorkerCompleted(对象发送方,runworkercompletedeventarge)
    {   
    //检查错误。。。
    ...
    //看看是否还有更多的工作要做
    如果(filelist.Count>0)
    {
    //重复任务
    BackgroundWorker worker=发件人作为BackgroundWorker;
    工人。道工();
    }
    }
    
    使用BackgroundWorkers,您还可以拥有独立的进度条等


    代码未经测试。

    这些辅助进程是否重叠?如中所示,这三个进程在运行时是否会相互影响?如果不是,则有三个(或n个)线程访问单个GetNextWorkItem
    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();
        }
    }