Synchronizing processes in C#

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I have the following situation:

Process 1 creates Process 2 (using Process.Start(startInfo)
Process 1 needs to wait until Process 2 is initialized before Process 1 can continue to execute
Both processes are non-GUI processes.

The problem that I am running into is that the Process.Start(startInfo) returns immediately to Process 1. Therefore, process 1 does not wait on its own for Process 2 to initialize.

Process 2 can take a few seconds to intialize. Process 1 needs to halt its execution until Process 2 is initialized. How can process 1 and 2 signal eachother to accomplish what I'm after?

In process 1 I tried using a Mutex:

Process process = Process.Start(startInfo);

if (process != null)
{
Mutex m = new Mutex(false, "Mutex");
m.WaitOne();
...
}

Process 2:

Main...
{
bool mutexWasCreated = false;
Mutex m = new Mutex(true, "Mutex", out mutexWasCreated);
if (mutexWasCreated)
{
...
m.ReleaseMutex();
}
}

this doesn't come close to working because process 1 gets the mutex before process 2 can acquire the lock. What I need is the ability to have process 1 wait on a mutex, have process 2 acquire the mutex lock, do its initialization, then release the mutex, then process 1 resumes execution.

I have gotten the above to work in C++ using the CreateEvent API. Process 1 creates an unsignaled event, process 1 launches process 2, process 1 waits on the event, process 2 does its thing, process 2 signals the event, process 1 continues.

How can I do this in C#?

Thanks!
 
You can use P/Invoke to access the Win32 CreateEvent API to create named
events. I created this test app fairly quicklly that seems to work...

in project 1


using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{


[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool
bManualReset,
bool bInitialState, string lpName);

[DllImport("kernel32.dll")]
static extern bool SetEvent(IntPtr hEvent);

[DllImport("kernel32.dll")]
static extern bool ResetEvent(IntPtr hEvent);


[DllImport("kernel32.dll", SetLastError=true)]
static extern int CloseHandle(IntPtr hObject);

const int ERROR_ALREADY_EXISTS = 183;


/// <summary>
///
/// </summary>
[STAThread]
static void Main(string[] args)
{
string file =
@"..\..\..\ConsoleApplication2\bin\debug\ConsoleApplication2.exe";
if ( !System.IO.File.Exists(file) )
{
Print("Unable to locate file {0}",file);
return;
}
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo(file,"2");
p.StartInfo = psi;

IntPtr handle;
bool createdNew;
if ( !CreateManagedEvent(out handle,out createdNew) )
{
Print("Error creating named event.");
return;
}

if ( !createdNew )
{
Print("App2 already running. Press any key to exit...");
Console.ReadLine();
return;
}
else
{
Console.WriteLine("Starting other app");
ManualResetEvent _evt = new ManualResetEvent(false);
_evt.Handle = handle;
_evt.Reset();
DateTime start = DateTime.Now;
p.Start();

Print("Waiting....");
_evt.WaitOne(TimeSpan.FromSeconds(15),false);
TimeSpan elapsed = DateTime.Now - start;
Print("Done waiting; it took {0} seconds...",elapsed.Seconds);
}
Print("All done");

}

/// <summary>
/// Creates a named event in the win32 space. This is a manual
/// reset event that is initially not signalled.
/// </summary>
/// <param name="handle"></param>
/// <param name="createdNew">true if it created a new one, false if it
opened an existing one</param>
/// <returns>true if it succeeds, otherwise false</returns>
static bool CreateManagedEvent(out IntPtr handle,out bool createdNew)
{
createdNew = false;
handle = CreateEvent(IntPtr.Zero, true,false, "MyNamedEvent");
int error = Marshal.GetLastWin32Error();
if ( handle == IntPtr.Zero )
return false;
createdNew = (error != ERROR_ALREADY_EXISTS);
return true;
}

static void Print(string format,params object[] args)
{
string msg = string.Format(format,args);
Trace.WriteLine(msg);
Console.WriteLine(msg);
}
}
}

in project 2


using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace ConsoleApplication2
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class2
{
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool
bManualReset,
bool bInitialState, string lpName);

[DllImport("kernel32.dll")]
static extern bool SetEvent(IntPtr hEvent);

[DllImport("kernel32.dll")]
static extern bool ResetEvent(IntPtr hEvent);


[DllImport("kernel32.dll", SetLastError=true)]
static extern int CloseHandle(IntPtr hObject);

const int ERROR_ALREADY_EXISTS = 183;

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
IntPtr handle;
bool createdNew;
if ( !CreateManagedEvent(out handle,out createdNew) )
{
Print("Error creating named event.");
return;
}

if ( createdNew )
{
Print("App1 not running yet, exiting after a 10 second wait...");
Thread.Sleep( TimeSpan.FromSeconds(10) );
return;
}
Print("Sleeping for a few seconds...");
Thread.Sleep( TimeSpan.FromSeconds(2) );
Print("Done sleeping, setting event...");
ManualResetEvent _evt = new ManualResetEvent(false);
_evt.Handle = handle;
_evt.Set();
Print("Sleeping for 10 more seconds...");
Thread.Sleep( TimeSpan.FromSeconds(10) );
Print("Done");
}
/// <summary>
/// Creates a named event in the win32 space. This is a manual
/// reset event that is initially not signalled.
/// </summary>
/// <param name="handle"></param>
/// <param name="createdNew">true if it created a new one, false if it
opened an existing one</param>
/// <returns>true if it succeeds, otherwise false</returns>
static bool CreateManagedEvent(out IntPtr handle,out bool createdNew)
{
createdNew = false;
handle = CreateEvent(IntPtr.Zero, true,false, "MyNamedEvent");
int error = Marshal.GetLastWin32Error();
if ( handle == IntPtr.Zero )
return false;
createdNew = (error != ERROR_ALREADY_EXISTS);
return true;
}

static void Print(string format,params object[] args)
{
string msg = string.Format(format,args);
Trace.WriteLine(msg);
Console.WriteLine(msg);
}


}
}





Chris B said:
I have the following situation:

Process 1 creates Process 2 (using Process.Start(startInfo)
Process 1 needs to wait until Process 2 is initialized before Process 1 can continue to execute
Both processes are non-GUI processes.

The problem that I am running into is that the Process.Start(startInfo)
returns immediately to Process 1. Therefore, process 1 does not wait on its
own for Process 2 to initialize.
Process 2 can take a few seconds to intialize. Process 1 needs to halt
its execution until Process 2 is initialized. How can process 1 and 2
signal eachother to accomplish what I'm after?
In process 1 I tried using a Mutex:

Process process = Process.Start(startInfo);

if (process != null)
{
Mutex m = new Mutex(false, "Mutex");
m.WaitOne();
...
}

Process 2:

Main...
{
bool mutexWasCreated = false;
Mutex m = new Mutex(true, "Mutex", out mutexWasCreated);
if (mutexWasCreated)
{
...
m.ReleaseMutex();
}
}

this doesn't come close to working because process 1 gets the mutex before
process 2 can acquire the lock. What I need is the ability to have process
1 wait on a mutex, have process 2 acquire the mutex lock, do its
initialization, then release the mutex, then process 1 resumes execution.
I have gotten the above to work in C++ using the CreateEvent API. Process
1 creates an unsignaled event, process 1 launches process 2, process 1 waits
on the event, process 2 does its thing, process 2 signals the event, process
1 continues.
 
Try looking into System.Threading.Mutex. As far as Im aware they
implement named events that do work across processes.

HTH
Kieran
 
To my knowledge mutexes are named but events are not. Do you have
information that contradicts this?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top