我想启动一堆子进程,然后在继续之前等待所有进程完成。一切正常。但我想在开始每个连续过程之间引入延迟。我面临的问题是来自子进程的退出事件可能在延迟期间发生,并且我无法在父进程处于睡眠状态时接收该事件。
请告知。以下是一些代码:
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
}
}
答案 0 :(得分:0)
我花时间实施了GrawCube的建议。以下代码将确保: 1)一次只启动MaxConcurrent进程(典型的,例如Quad上不超过4个进程) 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();
}
}
}
答案 1 :(得分:-1)
我认为您可能正在寻找Thread.Join方法? https://msdn.microsoft.com/en-us/library/system.threading.thread.join%28v=vs.110%29.aspx
允许您的父线程在子线程上等待。
答案 2 :(得分:-1)
我喜欢GrawCube建议的Timer解决方案。我没有使用计时器就实现了这个,但计时器解决方案可能更清洁。还可以通过Deadly-Bagel发布我修改的原始代码来添加延迟和cpu阈值。这是代码:
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
}
}
}
}