2015-02-25 2 views
0

Я хочу запустить кучу дочерних процессов, а затем дождаться завершения всех процессов перед продолжением. Все работает нормально. Но я хочу ввести задержку между началом каждого последовательного процесса. Проблема, с которой я сталкиваюсь, заключается в том, что событие Exited из дочернего процесса может произойти во время задержки, и я не могу принять это событие в родительском процессе, пока он спит.Process.Exited не возникает, когда родительский процесс ожидает

пожалуйста совет.

Вот код:

public void SetupProcess(string program, string args) 
    { 
     cmd = new Process(); 
     cmd.StartInfo.FileName = program; 
     cmd.StartInfo.Arguments = args; 
     cmd.EnableRaisingEvents = true; 
     //cmd.StartInfo.Verb = "Print"; 
     cmd.StartInfo.CreateNoWindow = true; 
     cmd.Exited += new EventHandler(cmd_Exited); 
    } 

    public bool StartProcess(int delay) 
    { 
     bool retval = false; 
     if (cmd.Start()) 
     { 
      Thread.Sleep(delay); 
     } 
     return retval; 
    } 


    private void cmd_Exited(object sender, EventArgs e) 
    { 
     pIsRunning = false; 
     if (Exited != null) 
     { 
      Console.WriteLine("Process exited. notfying queue..."); 
      Exited(this, null); // signal the queue to run the next process 
     } 
    } 
+1

Как вы запуская процессы? Как вы ждете? Пожалуйста, покажите код. – cubrr

+0

GrawCube, это похоже на то, что предположил Deadly Bagel, но с фактором задержки, который является причиной проблемы, –

+0

Спасибо за фрагмент кода. Если вы хотите, чтобы ваш основной поток оставался отзывчивым, почему бы не использовать таймер, чтобы начать «кучу процессов»? Создайте стек процессов, чтобы запустить и использовать таймер 'Elapsed', чтобы поп и запустить процессы. – cubrr

ответ

-1

Я думаю, что вы можете искать методом Thread.join? https://msdn.microsoft.com/en-us/library/system.threading.thread.join%28v=vs.110%29.aspx

Это позволяет вашему родительскому потоку ждать дочернего потока.

+0

Я говорю о разных процессах здесь! поэтому ваше предложение не применимо. –

+0

Я понял, что после того, как вы опубликовали код, но к тому времени уже проголосовали. О, хорошо ... я виноват, что не использовал комментарии, чтобы получить разъяснения. – TechneWare

-1

Мне нравится решение таймера, предлагаемое GrawCube. Я реализовал это без использования таймера, но решение таймера может быть более чистым. Кредит также отправляется в Deadly-Bagel для публикации исходного кода, который я модифицировал, чтобы добавить задержку и порог процессора. Вот код:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ProcessEx s = new ProcessEx(); 
     s.SetupProcess(@"C:\MyP\MBN\Dev\Test\Hello\bin\Debug\Hello.exe", "process 0"); 
     ProcessExQueue q = new ProcessExQueue(); 
     q.Add(s); 
     s = new ProcessEx(); 
     s.SetupProcess(@"C:\MyP\MBN\Dev\Test\Hello\bin\Debug\Hello.exe", "process 1"); 
     q.Add(s); 

     s = new ProcessEx(); 
     s.SetupProcess(@"C:\MyP\MBN\Dev\Test\Hello\bin\Debug\Hello.exe", "process 2"); 
     q.Add(s); 

     Thread t = new Thread(q.StartFirstProcesses); 
     t.Start(); 
     Console.ReadKey(); 


    } 
} 

class ProcessExQueue 
{ 
    private List<ProcessEx> Servers = new List<ProcessEx>(); 
    public int MaxConcurrent { get; set; } 
    public int Delay { get; set; } 
    byte _running = 0; 

    public ProcessExQueue() 
    { 
     MaxConcurrent = 4; 
     Delay = 60000; 
    } 

    public void Add(ProcessEx Server) 
    { 
     Servers.Add(Server); 
     Server.Exited += cmd_Exited; 
     Server.Started += cmd_Started; 
    } 

    private bool RunNextProcess() 
    { 
     bool retval = false; 
     if (Servers.Count > 0) 
     { 
      ProcessEx ToRun = Servers[0]; 
      Servers.Remove(ToRun); 
      retval = ToRun.StartProcess(); 
      if (retval) 
       lock (this) 
       { 
        _running++; 
       } 
     } 
     Console.WriteLine("Thread Id {0} will sleep...", Thread.CurrentThread.ManagedThreadId); 
     Thread.Sleep(Delay); 
     Console.WriteLine("Thread Id {0} woke up", Thread.CurrentThread.ManagedThreadId); 
     return retval; 
    } 

    public void StartFirstProcesses() 
    { 
     while (Servers.Count > 0 && _running <= MaxConcurrent) 
     { 
      RunNextProcess(); 
     } 
    } 

    private void cmd_Exited(object sender, EventArgs e) 
    { 
     lock (this) 
     { 
      _running--; 
     } 
     Console.WriteLine("Queue: process exited {0}.", ((ProcessEx)sender).GetPID()); 
     if(Servers.Count > 0 && _running <= MaxConcurrent) 
     { 
      RunNextProcess(); 
     } 
    } 

    private void cmd_Started(object sender, EventArgs e) 
    { 
     Console.WriteLine("Queue: process started {0}", ((ProcessEx)sender).GetPID()); 
    } 
} 

class ProcessEx 
{ 
    public bool IsRunning 
    { 
     get 
     { 
      return pIsRunning; 
     } 
    } 

    private bool pIsRunning = false; 

    public delegate void OutputEventHandler(ProcessEx sender, string Output, bool IsError); 

    public delegate void StatusEventHandler(ProcessEx sender, EventArgs e); 


    public event StatusEventHandler Started; 
    public event StatusEventHandler Exited; 

    private Process cmd; 

    public int GetPID() 
    { 
     return cmd.Id; 
    } 

    public bool StartProcess() 
    { 
     bool retval = false; 
     if (cmd.Start()) 
     { 
      pIsRunning = true; 
      retval = true; 
      Console.WriteLine("Running {0} {1}", cmd.StartInfo.FileName, cmd.StartInfo.Arguments); 
      Console.WriteLine("Process Id {0}", cmd.Id); 
      if (Started != null) 
       Started(this, null); 
     } 
     return retval; 
    } 

    public void KillProcess() 
    { 
     if (IsRunning) 
     { 
      cmd.Kill(); 
     } 
    } 

    public void SetupProcess(string program, string args) 
    { 
     // https://msdn.microsoft.com/en-us/library/h6ak8zt5(v=vs.110).aspx 
     cmd = new Process(); 
     cmd.StartInfo.FileName = program; 
     cmd.StartInfo.Arguments = args; 
     cmd.EnableRaisingEvents = true; 
     //cmd.StartInfo.Verb = "Print"; 
     cmd.StartInfo.CreateNoWindow = true; 
     cmd.Exited += new EventHandler(cmd_Exited); 
    } 

    private void cmd_Exited(object sender, EventArgs e) 
    { 
     pIsRunning = false; 
     if (Exited != null) 
     { 
      Console.WriteLine("thread {0} received exit signal", Thread.CurrentThread.ManagedThreadId); 
      Console.WriteLine("Process {0} exited. notfying queue...", ((Process)sender).Id); 
      Exited(this, null); // signal the queue to run the next process 
     } 
    } 

} 

}

0

Я взял время, чтобы реализовать предложение GrawCube в. Приведенный ниже код гарантирует: 1) Не более чем за несколько минут запускаются процессы MaxConcurrent (типичные, например, не более 4 процессов на Quad) 2) Существует определенная Задержка, введенная между началом последовательного процесса (в моем случае служба сообщений ввел это ограничение)

Вот код, надежда, что помогает:

class ProcessExQueue 
    { 
     public int MaxConcurrent { get; set; } 
     public int Delay { get; set; } 
     public Action Done; 
     private List<Timer> _timers; 

     private List<ProcessEx> Servers = new List<ProcessEx>(); 
     byte _running = 0; 
     private DateTime _lastStart; 

     public ProcessExQueue() 
     { 
      MaxConcurrent = 4; 
      Delay = 15000; 
      _timers = new List<Timer>(); 
     } 

     public void Add(ProcessEx Server) 
     { 
      Servers.Add(Server); 
      Server.Exited += cmd_Exited; 
      Server.Started += cmd_Started; 
     } 

     public void RunProcessTimer(int delay) 
     { 
      System.Timers.Timer timer = new System.Timers.Timer(); 
      timer.Elapsed += new System.Timers.ElapsedEventHandler(DoTask); 
      timer.Interval = delay; 
      timer.AutoReset = false; // only first time 
      timer.Start(); 
      _timers.Add(timer); 
      Console.WriteLine("timer started with delay {0} @ {1} ", delay, DateTime.Now); 
     } 

     void DoTask(object source, System.Timers.ElapsedEventArgs e) 
     { 
      Console.WriteLine("timer call @ {0}", DateTime.Now); 
      lock (this) 
      { 
       if (Servers.Count > 0 && _running <= MaxConcurrent) 
       { 
        ProcessEx ToRun = Servers[0]; 
        ToRun.Starter = (Timer)source; 
        Servers.Remove(ToRun); 
        bool success = ToRun.StartProcess(); 
        if (success) 
         _running++; 
       } 
       else 
       { 
        Console.WriteLine("nothing started, queue size {0} running {1}", Servers.Count, _running); 
       } 
      } 
     } 

     public void StartFirstProcesses() 
     { 
      for (int i = 0; i < Servers.Count; i++) 
      { 
       RunProcessTimer(i == 0 ? 1000 : Delay*(i)); 
      } 
     } 

     private void cmd_Exited(object sender, EventArgs e) 
     { 
      Console.WriteLine("Queue: process exited {0}.", ((ProcessEx)sender).GetPID()); 

      // find the timer and get rid of it; 
      //TODO 

      Timer found = _timers.FirstOrDefault(t => t == ((ProcessEx)sender).Starter); 
      if (found != null) 
      { 
       found.Enabled = false; 
      } 

      lock (this) 
      { 
       _running--; 
      } 

      if (Servers.Count == 0) // no more processes to run 
      { 
       Console.WriteLine("No more processes to run. some threads may be asleep"); 
       if (_running == 0) 
       { 
        Console.WriteLine("disarming all timers"); 
        _timers.ForEach(t=> t.Enabled=false); 
        Done(); 
       } 
      } 
      else 
      { 
       if (Servers.Count > 0 && _running <= MaxConcurrent) 
       { 
        TimeSpan tspan = (DateTime.Now - _lastStart); 
        RunProcessTimer(tspan.Milliseconds < Delay?Delay - tspan.Milliseconds:1); 
       } 
      } 
     } 

     private void cmd_Started(object sender, EventArgs e) 
     { 
      Console.WriteLine("Queue: process started {0}", ((ProcessEx)sender).GetPID()); 
      _lastStart = DateTime.Now; 
     } 
    } 

    class ProcessEx 
    { 
     public Timer Starter { get; set; } 

     public bool IsRunning 
     { 
      get 
      { 
       return pIsRunning; 
      } 
     } 

     private bool pIsRunning = false; 

     public delegate void OutputEventHandler(ProcessEx sender, string Output, bool IsError); 

     public delegate void StatusEventHandler(ProcessEx sender, EventArgs e); 

     public event StatusEventHandler Started; 

     public event StatusEventHandler Exited; 

     private Process cmd; 

     public int GetPID() 
     { 
      return cmd.Id; 
     } 

     public bool StartProcess() 
     { 
      bool retval = false; 
      if (cmd.Start()) 
      { 
       pIsRunning = true; 
       retval = true; 
       Console.WriteLine("Running {0} {1}", cmd.StartInfo.FileName, cmd.StartInfo.Arguments); 
       Console.WriteLine("Process Id {0}", cmd.Id); 
       if (Started != null) 
        Started(this, null); 
      } 
      return retval; 
     } 

     public void KillProcess() 
     { 
      if (IsRunning) 
      { 
       cmd.Kill(); 
      } 
     } 

     public void SetupProcess(string program, string args) 
     { 
      cmd = new Process(); 
      cmd.StartInfo.FileName = program; 
      cmd.StartInfo.Arguments = args; 
      cmd.EnableRaisingEvents = true; 
      //cmd.StartInfo.Verb = "Print"; 
      cmd.StartInfo.CreateNoWindow = true; 
      cmd.Exited += new EventHandler(cmd_Exited); 
     } 

     private void cmd_Exited(object sender, EventArgs e) 
     { 
      pIsRunning = false; 
      if (Exited != null) 
      { 
       Console.WriteLine("thread {0} received exit signal", Thread.CurrentThread.ManagedThreadId); 
       Console.WriteLine("Process {0} exited. notfying queue...", ((Process)sender).Id); 
       Exited(this, null); // signal the queue to run the next process 
      } 
     } 

    } 

// usage 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      ProcessEx s = new ProcessEx(); 
      s.SetupProcess(@"C:\MyP\MBN\Dev\Test\Hello\bin\Debug\Hello.exe", "process 0"); 
      ProcessExQueue q = new ProcessExQueue(); 
      q.Add(s); 
      s = new ProcessEx(); 
      s.SetupProcess(@"C:\MyP\MBN\Dev\Test\Hello\bin\Debug\Hello.exe", "process 1"); 
      q.Add(s); 

      s = new ProcessEx(); 
      s.SetupProcess(@"C:\MyP\MBN\Dev\Test\Hello\bin\Debug\Hello.exe", "process 2"); 
      q.Add(s); 

      q.Done =() => Console.WriteLine("Done!"); 

      q.StartFirstProcesses(); 
      /* 
      Thread t = new Thread(q.StartFirstProcesses); 
      t.Start(); 
      */ 
      Console.ReadKey(); 
     } 
    } 
// sample process 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      if (args.Count() > 0) 
      { 
       Console.WriteLine(Process.GetCurrentProcess().Id); 
       Thread.Sleep(5000); 
       Console.WriteLine("exiting... press any key"); 
       Console.ReadKey(); 
      } 
     } 
    }