Synchronizing processes in C#

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!
 
D

David Levine

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.
 
G

Guest

Try using the following classes instead

AutoResetEvent
ManualResetEvent

Andy Cooper
 
K

Kieran Benton

Try looking into System.Threading.Mutex. As far as Im aware they
implement named events that do work across processes.

HTH
Kieran
 
D

David Levine

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

Top