Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
In some previous posts (Out of Process IPC/TCP Remoting code, .Net Remoting (AppDomains, Out of Process, Two Way, etc..)) I showed some sample code using .Net remoting over a process boundary. As a result, I received a few questions about the process creation and how to handle the process coordination (i.e., The Host/Master process waiting on the created process startup). I apologize to those who have been waiting for another sample on the subject, but I have been pretty busy as of late.
The attached sample code shows the following;
1. How to ensure the Host Process waits on the new process creation.
a. Previously I showed a simple *hack* where the created process sleeps for a while in order to let the process creation complete.
b. A much cleaner and more reliable solution uses EventWaitHandle.
2. The created Process runs until the Host Process is terminated or the Host terminates the new process.
a. Previously I showed a simple *hack* where the created process does a Console.ReadLine() in order to halt code execution and thus cause process termination.
b. I didn’t show an example of how the created process can shutdown in the event the Host process shuts down. This scenario covers orphaned processes.
c. The solution: System.Diagnostics.Process.GetProcessById(HostPID).WaitForExit();
View Source for Host Process: Show Code ...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;
namespace SampleWaitForProcessStartup
{
class Program
{
static void Main(string[] args)
{
String CurrentProcessInfo = String.Format(CultureInfo.InvariantCulture
, "Host Process:{0}, PID:{1}"
, Process.GetCurrentProcess().ProcessName
, Process.GetCurrentProcess().Id.ToString());
Console.WriteLine(CurrentProcessInfo + ", Running.");
int TIMEOUT_SECONDS = 5;
Guid GUID = Guid.NewGuid();
String NewProcessArgs = String.Format(CultureInfo.InvariantCulture
, "{0} {1}"
, GUID.ToString()
, Process.GetCurrentProcess().Id.ToString());
Process NewProcess = new Process();
NewProcess.StartInfo.FileName = Environment.CurrentDirectory + "\\SampleProcess.exe";
NewProcess.StartInfo.CreateNoWindow = false;
NewProcess.StartInfo.Arguments = NewProcessArgs;
NewProcess.StartInfo.UseShellExecute = false;
// Wait until the process we are creating is ready.
// Appending a unique identifier to the external process handle which also aids in debugging.
EventWaitHandle readyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, "SampleProcess:" + GUID.ToString());
NewProcess.Start();
// wait nSeconds for the process to start
bool success = readyEvent.WaitOne(new TimeSpan(0, 0, TIMEOUT_SECONDS), false);
readyEvent.Close();
if (!success)
{
// Try to avoid leaving a half-baked process around if possible.
try
{
NewProcess.Kill();
}
catch (Exception) { }
}
Console.WriteLine("Press <Enter> to shut down the Host Process and in turn the New/Created process should shut down.");
Console.ReadLine();
}
}
}
View Source for Created Process: Show Code ...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;
namespace SampleProcess
{
class Program
{
/// <summary>
/// This is a sample console app that is started up by a Host process (e.g., "SampleWaitForProcessStartup").
/// It is difficult to ensure that a managed process (i.e., this app) is started completely by a Host app/process
/// before communicating between the processes. Most people use a less determisitic aproach by putting a
/// sleep timer in the process they are starting up.
/// </summary>
/// <param name="args">
/// Arg1: A unique identifier of this process. The parm is passed on the command line to
/// this process that is started.
/// Arg2: PID of the Host Process. In the event the Host process shuts down, so whould we.</param>
static int Main(string[] args)
{
TimeSpan waitTime = new TimeSpan(0, 0, 10);
// We will use the convention that a process exit value of 0 == sucess.
// This also allows command line tasks to "catch a bad process exit".
if (args == null || args.Length != 2 || args[0].Length != 36)
return 1;
string GUID = args[0];
int HostPID = Convert.ToInt32(args[1], CultureInfo.InvariantCulture);
// Prepend "ProcessName" to unique identifier (i.e., per process) for wait handle. This is
// also handy when debugging.
// If you attach a VS debugger to a running process, then press the pause icon,
// you can see local variables and the GUID that was passed to help identify the spawned process.
string CurrentProcessName = System.Diagnostics.Process.GetCurrentProcess().ProcessName + ":" + GUID;
String CurrentProcessInfo = String.Format(CultureInfo.InvariantCulture, "Process:{0}, PID:{1}"
, CurrentProcessName, Process.GetCurrentProcess().Id.ToString());
Console.WriteLine(CurrentProcessInfo + ", Starting.");
// Signal to the host process that we are ready for communication.
EventWaitHandle readyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, CurrentProcessName);
// Uncomment out the next line in order to test killing this process if it does not startup within
// the Host process requested timeout.
//Thread.Sleep(waitTime);
readyEvent.Set();
readyEvent.Close();
Console.WriteLine(CurrentProcessInfo + ", Started.");
try
{
Console.WriteLine("Waiting on Host Process PID (" + HostPID.ToString() + ") to exit.");
System.Diagnostics.Process.GetProcessById(HostPID).WaitForExit();
}
catch
{
// The host may have shut down before we could wait on it.
Environment.Exit(1);
return 1;
}
Environment.Exit(0);
return 0;
}
}
}
- Anonymous
May 29, 2009
PingBack from http://paidsurveyshub.info/story.php?title=jack-gudenkauf-jackg-weblog-process-creation-and-coordination