|
-
October 2nd, 2011, 06:17 AM
#13
Re: Sharing objects between application instances using WCF
Thanks for your opinion. 
 Originally Posted by Arjay
I think you have some issues with regard to the use of the manualset event.
I'd say the prevalent issue here is that (and why) I didn't encounter any issue in the SimulStart run documented in the log. 
I see it's a manual reset named event, but I don't see where you set it or reset it. If you don't ever set it, then won't WaitOne(0) always false?
It gets set and reset in these two static Server methods that are called from the server form class' c'tor and d'tor (lines highlighted in red):
Code:
// To be called upon start-up of the supposedly singular primary server .exe instance,
// returns true if no other instance is running yet, i.e. the "launched" event was not set:
bool Server::Startup(Action ^dltShutdownRequestCallback, Action<int> ^dltStatusReportCallback)
{
LOG_FUNCTION_ENTRY
EventWaitHandle ^evt = gcnew EventWaitHandle(false, EventResetMode::ManualReset, "WcfShareTestServerLaunchedEvent");
if (evt->WaitOne(0)) {
evt->Close();
Log::GetInstance()->WriteLine("Leaving " __FUNCSIG__ " (failure)");
return false; // Start-up failed: primary instance already running
}
s_evtServerLaunched = evt;
s_dltShutdownRequestCallback = dltShutdownRequestCallback;
s_dltStatusReportCallback = dltStatusReportCallback;
s_host = gcnew ServiceHost(Server::typeid, gcnew Uri("net.pipe://localhost/TestServer"));
s_host->Open();
evt->Set();
Log::GetInstance()->WriteLine("Leaving " __FUNCSIG__ " (success)");
return true;
}
// To be called upon shutdown of the singular server .exe instance:
void Server::Shutdown()
{
LOG_FUNCTION_ENTRY
if (s_evtServerLaunched) {
s_evtServerLaunched->Reset();
s_evtServerLaunched->Close();
}
if (s_host) s_host->Close();
LOG_FUNCTION_EXIT
}
At any rate, you might consider using a named mutex to protect the server initialization code.
Code:
bool mutexWasCreated;
Mutex^ m = gcnew Mutex( false, "WcfShareTestServerLaunchedEvent", mutexWasCreated );
// Block other processes
m->WaitOne( );
// Start up the server
if( mutexWasCreated )
{
// Startup up WCF server
}
// Allow access to other processes
m->ReleaseMutex( );
The code above should block additional processes from attempting to access the server while its initializing.
I'd say that's functionally equivalent or at least quite similar to what I actually used in the Remoting test scenario (and almost literally identical to what I currently use in the real-life app to protect the SMTP server/user name pair). However, I always found the way I test for a server instance already running during client start-up (in Server::GetInstance()) a bit awkward.
For the dual use it has here, i.e. both protecting the singular server instance and indicating/signaling that the server runs on the client side, I found the solution using an event instead of the mutex more straightforward and elegant. One particular advantage of the event here is that, unlike a mutex, it gets signaled when it is set, not when it is released. And that allowed me to use the following code in the client start-up:
Code:
EventWaitHandle ^evt = gcnew EventWaitHandle(false, EventResetMode::ManualReset, "WcfShareTestServerLaunchedEvent");
if (!evt->WaitOne(0)) { // This means the server isn't running yet, so start it
log->WriteLine("Starting server app...");
Process ^proc = Process::Start(Path::Combine(Application::StartupPath, "TestServer.exe"));
Trace::Assert(proc != nullptr, "WCF Share Test: Failed to launch TestServer");
log->WriteLine("Waiting for server start-up...");
Trace::Assert(evt->WaitOne(10000), "WCF Share Test: Wait for TestServer start-up timed out");
proc->Close();
log->WriteLine("Server app started");
}
evt->Close();
The main reason why handling it that way became necessary was that, unlike Remoting, WCF doesn't tolerate an attempt to connect to the server when that hasn't finished start-up yet, so I was in need of a way to wait for server start-up to finish.
One additional thing your post and the thoughts I had while writing this post made me consider is, though, whether it might be a good idea to protect the phase from the creation of the event object to the first highlighted line in the first code snippet above by an additional global mutex.
BTW, can't lines 3 to 6 of your code snippet be contracted to:
Code:
Mutex^ m = gcnew Mutex( true, "WcfShareTestServerLaunchedEvent", mutexWasCreated );
Last edited by Eri523; October 2nd, 2011 at 06:21 AM.
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|