I've detected a certain behaviour in my code that I'm unable to explain and even though it's working fine, not fully understanding what's going on is really bothering me.
The script below creates and runs n_total
processes of notepad but only allows a maximum of n_cpus
notepads running at each time. In the beginning, n_cpus
processes are launched and the rest only begin if the one or more running notepads terminate. Each notepad process can be terminated by the user simply by closing its window which triggers the event Process.Exited in the code. Now, inside the loop, the variable p
is re-used to instantiate the class Process every time a new notepad is required and every object p
subscribes to the event Process.Exited by p.Exited += p_Exited;
Consider that we have n_cpus = 3
and run the code until it generates those 3 simultaneous notepads. I would expect that only the last instance p
would fire the event since I'm re-using p
and p.Exited
belongs to the object, but no... No matter what notepad I close, the event is fired and a new notepad appears. What's going on? Is there some kind of objectless list of delegates EventHandler that remembers every process I create?
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
// Summary: generates processes for "n_total" notepads allowing for a maximum of "n_cpus"
// notepads at each time. Every time a notepad closes another appears until all are run.
// A single variable "p" instantiates the class "Process" and the event "p.Exited"
// updates the number of running processes "n_running".
static int n_running = 0; // number of notepads running each time
static void Main()
{
int n_cpus = 3;
int n_total = 3 * n_cpus;
int i_run = 0;
while (i_run < n_total) // Process generating routine until all are run
{
if (n_running < n_cpus) // Only a maximum of n_cpus running at each time
{
n_running++;
i_run++;
Process p = new Process(); // A new object per process
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c notepad.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.EnableRaisingEvents = true;
p.Exited += p_Exited; // Is this associated with a particular object "p", right?
p.Start();
}
else Thread.Sleep(1000); // Waits 1s before checking for new terminated processes
}
}
static private void p_Exited(object sender, EventArgs e)
{
n_running--; // Updates the number of active processes. Triggers new future processes
}
}