Semaphores and .NET

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

Guest

I have a C# application and a VB6 application that need to share a dialup
connection to the internet. Don't ask why, this is one of those corporate "do
or die" things.

The only way I can see to do this is by using the combination of a MUTEX to
create a Cross-application Singleton for the Dialing operation and a Named
Semphore that can keep a count of how many processes are currently sharing
the connection from the client's workstation into our corporate VPN extranet.
I am trying to find an example of how to manage semaphores in C# in a class.
I will have to translate the same into the VB6 for the legacy app.

Using .NET 2.0 is not an option, they won't let me use a BETA. Neither is
remoting. I have to make the access sharable between executables modules.
Does any one have any ideas.
 
Bobby;

Again, I don't think any one understands that these are 2 spearate
executables. Monitor won't do it. It has to be something similar to MUTEX but
will allow a certain number of executables to share the Connection to the
internet and will prevent which ever one completes first from hanging up on
the second one. The MUTEX would only prevent one from dialing while the other
one is dialing. The Semaphore tracks how many active transfers are going on
simultaneously.

Please any more ideas.
 
A week ago, I posted a sample implementation of semaphore using Win32 API.
This solution can be adjusted so the semaphore handle can be shared among
processes, which will suit your needs, if I understand what you need to
accomplish.
This is were the implementation is posted
http://www.pcreview.co.uk/forums/printthread.php?t=2099193
have a look at MSDN for settings you need to change when handle should be
shared among processes.
 
I guess you should consider me dumb as dirt, because I can't see how I can
implement this in such a way that all processes will have access to the same
named semaphore when the only constructor that implements the name is
protected in your example. I am not being factious, I just don't understand.
Most of this is brand new to me and I seem to keep getting thrown the
projects that would even give MSDN MVP's pause for thought.

Would you please explain this a little further, Lebesgue, so that even a
clod like me could understand.

Thanks.
--
Kenneth A. Jinks, Jr.
Lead Project Software Engineer
LabCorp CPG - LCM Development
Huntsville, AL
 
I guess you should consider me dumb as dirt, because I can't see how I can
implement this in such a way that all processes will have access to the same
named semaphore when the only constructor that implements the name is
protected in your example. I am not being factious, I just don't understand.
Most of this is brand new to me and I seem to keep getting thrown the
projects that would even give MSDN MVP's pause for thought.

Would you please explain this a little further, Lebesgue, so that even a
clod like me could understand.

Thanks.
--
Kenneth A. Jinks, Jr.
Lead Project Software Engineer
LabCorp CPG - LCM Development
Huntsville, AL
 
I guess you should consider me dumb as dirt, because I can't see how I can
implement this in such a way that all processes will have access to the same
named semaphore when the only constructor that implements the name is
protected in your example. I am not being factious, I just don't understand.
Most of this is brand new to me and I seem to keep getting thrown the
projects that would even give MSDN MVP's pause for thought.

Would you please explain this a little further, Lebesgue, so that even a
clod like me could understand.

Thanks.
--
Kenneth A. Jinks, Jr.
Lead Project Software Engineer
LabCorp CPG - LCM Development
Huntsville, AL
 
Hi Kenneth!
I am sorry for possible confusion, but I just realized that semaphore
objects can be only inherited among processes, not shared across the whole
system.
I just didn't remember well the thing about SECURITY_ATTRIBUTES mentioned
here
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createsemaphore.asp

"SECURITY_ATTRIBUTES structure that determines whether the returned handle
can be inherited by child processes"

Again, I apologize for confusion.
 
I just got an idea how one would be able to accomplish this, maybe...

I thought of creating a file, using a Mutex to serialize writes to it and
write a single byte when you would be acquiring semaphore and deleting the
last byte when releasing it with checks and possibly a pooling mechanism
used as waiting for semaphore to be signalled (reading that file at
periodical intervals).
Maybe someone will find this like a dumb idea, but at the moment I don't see
a reason why this wouldn't work, and when you have no other possibility,
even a dumb solution is better than no at all.

Just my idea, hope it can be helpful
 
jinksk said:
Again, I don't think any one understands that these are 2 spearate
executables. Monitor won't do it. It has to be something similar to
MUTEX but will allow a certain number of executables to share the
Connection to the internet and will prevent which ever one completes
first from hanging up on the second one. The MUTEX would only prevent
one from dialing while the other one is dialing. The Semaphore tracks
how many active transfers are going on simultaneously.

I have some code here which may help. Honestly, I don't remember testing
this, I threw it together because I thought I needed it and decided to do
something different. Sorry if it doesn't work.

namespace System.Threading
{
using System;
using System.Threading;
using System.Runtime.CompilerServices;

public sealed class Semaphore : WaitHandle
{

public Semaphore(long initialCount, long maximumCount, String
name, out bool createdNew)
{
IntPtr semaphoreHandle = CreateSemaphoreNative(initialCount,
maximumCount, name, out createdNew); // throws a Win32 exception if
failed to create a semaphore
Handle = semaphoreHandle;
}
public Semaphore(long initialCount, long maximumCount, String
name)
{
bool createdNew;
IntPtr semaphoreHandle = CreateSemaphoreNative(initialCount,
maximumCount, name, out createdNew); // throws a Win32 exception if
failed to create a semaphore
Handle = semaphoreHandle;
}
public Semaphore(long initialCount, long maximumCount)
{
bool createdNew;
IntPtr semaphoreHandle = CreateSemaphoreNative(initialCount,
maximumCount, null, out createdNew); // throws a Win32 exception if
failed to create a semaphore
Handle = semaphoreHandle;
}
public Semaphore(long maximumCount)
{
bool createdNew;
IntPtr semaphoreHandle = CreateSemaphoreNative(0,
maximumCount, null, out createdNew); // throws a Win32 exception if
failed to create a semaphore
Handle = semaphoreHandle;
}

public void ReleaseSemaphore(long releaseCount, out long
previousCount)
{
ReleaseSemaphoreNative(Handle, releaseCount, out
previousCount);
}

public void ReleaseSemaphore(long releaseCount)
{
long previousCount;
ReleaseSemaphoreNative(Handle, releaseCount, out
previousCount);
}

public void ReleaseSemaphore()
{
long previousCount;
ReleaseSemaphoreNative(Handle, 1, out previousCount);
}

[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern private static IntPtr CreateSemaphoreNative(long
initialCount, long maximumCount, String name, out bool createdNew);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern private static void ReleaseSemaphoreNative(IntPtr handle,
long releaseCount, out long previousCount);

}
}


--
Reginald Blue
"I have always wished that my computer would be as easy to use as my
telephone. My wish has come true. I no longer know how to use my
telephone."
- Bjarne Stroustrup (originator of C++) [quoted at the 2003
International Conference on Intelligent User Interfaces]
 
Dear Mr. Stacey,
as you seem not to figure out, Kenneth needs a semaphore which would be
shared among two processes. Your semaphore implementation published on
CodeProject is not a choice for him (not to forget the deadlock problem you
have with it)
 
William;
Thanks for your advice and the code but this still does not solve the
problem. The two applications are two separate executables that run
simultaneously and need to share resources. Actually there are three;
however, the customers I have to get this working for use only two of them.
The Monitor class only works within a single application. It can only limit
access to objects created by that executable and its underlying threads. A
seperate executable does not have access to the same instance of the Monitor
class that was created by the first stand alone application.

What I need is a method to synchronize access to the RAS system where
one stand-alone application does not interfere with the access to the RAS,
DUNS, and Internet of another stand-alone application: given that I control
the source code for both. We do not have the luxury at this time of
completely re-writing the VB6 app in C# or even porting it to VB.NET. I am
the only one working on the connectivity part of these two applications and I
also have to handle the hand-written EDI translaters for the project. I have
until the end of September to accomplish this.

I know, you probably get projects like this thrown in your face every
day. Let me just put the overview out for you for just a minute.

1.) We have 2 separate stand-alone applications we use to transmit data over
the Internet via a IPSec VPN.

2.) The newest of these is written almost completely in C#.NET and only uses
1 ActiveX component: a Dialer from Catalyst. This application will eventually
take over all of our connectivity needs except for faxing.

3.) The older stand-alone application is written in VB6 and uses the old
Cresent Internet Controls. We still conduct our primary transfers via this
app (where the $$$'s go).

4.) They want me to create a means by which if one of these dials into the
VPN first and then the second needs access as well to have the second skip
the dialer routine (that part I've got figured out) and go ahead and log into
the remote host.

5.) Now comes the tricky part, if the first app finishes its transfer before
the second one, it cannot hangup the connection. And visa versa. Only when no
one else is connected can the IPSec tunnel be dropped.

See the dilema?
--
Kenneth A. Jinks, Jr.
Lead Project Software Engineer
LabCorp CPG - LCM Development
Huntsville, AL
 
As I said, he could modify it pretty easy. Instead of monitor, use a named
mutex and shared file to hold the count or mem mapped file, etc. Mind
sharing what deadlock problem there is? I would be happy to fix it. TIA.
 
Change the monitor to a named mutex and use a mem mapped file to hold the
shared counter (or plain disk file).
 
William Stacey said:
As I said, he could modify it pretty easy. Instead of monitor, use a named
mutex and shared file to hold the count or mem mapped file, etc. Mind
sharing what deadlock problem there is? I would be happy to fix it. TIA.

As stated in the discussion under your article:
(http://www.codeproject.com/csharp/DijkstraCountingSemaphore.asp#xx1185086xx
)

public bool Acquire(int millisecondsTimeout)
{
lock(syncLock)
{
...snip...
Monitor.Wait(syncLock, millisecondsTimeout)
...snip...
}
}
public void Release(int releaseCount)
{
...snip...
lock(syncLock)
{
...snip...
Monitor.PulseAll(syncLock);
...snip...
}
}



To aquire a lock on the semaphore, you need to obtain syncLock (which is
released the moment you leave the function). If there are no slots
available, you block at the Monitor.Wait() call, INSIDE the lock statement.
When a different thread finishes up and tries to release, it attempts to
aquire the exclusive lock on syncLock. Since there is a thread blocking on
Monitor.Wait() inside the lock, this won't release.
 
Monitor.Wait releases the lock.

Lebesgue said:
As stated in the discussion under your article:
(http://www.codeproject.com/csharp/DijkstraCountingSemaphore.asp#xx1185086xx
)

public bool Acquire(int millisecondsTimeout)
{
lock(syncLock)
{
...snip...
Monitor.Wait(syncLock, millisecondsTimeout)
...snip...
}
}
public void Release(int releaseCount)
{
...snip...
lock(syncLock)
{
...snip...
Monitor.PulseAll(syncLock);
...snip...
}
}



To aquire a lock on the semaphore, you need to obtain syncLock (which is
released the moment you leave the function). If there are no slots
available, you block at the Monitor.Wait() call, INSIDE the lock
statement.
When a different thread finishes up and tries to release, it attempts to
aquire the exclusive lock on syncLock. Since there is a thread blocking on
Monitor.Wait() inside the lock, this won't release.
 
As Nigel correctly points out, the implementation is correct and a well
known pattern in this type of producer-consumer locking patterns.
Monitor.Wait releases the lock so a thread calling Release is not blocked.
The lock will be reacquired for the Acquire thread *before Monitor.Wait
returns (unless there is a timeout or some mutex exception) - so the rest of
the code is still "inside" the lock. The monitor queue itself will
determine which thread gets the lock after a Pulse operation - but only one
thread will receive the lock and be able to continue on. So the pattern is
sound and well-known.
 

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