views:

94

answers:

2

I am working on a client server system, and am running into issues where multiple clients are executing an action at the same time. We are able to solve this by locking on the critical section of code, which ensures that the first client will complete the action before the second client enters the code block. My question is this: our server is also clustered, so multiple instances of the server itself can exist, which recreates the same problem as before. How could we solve this problem? Thanks!

To expand on the problem: The first user is checking if an action is valid and getting a yes response. The second user is checking if an action is valid and also getting a yes response before the first user completes his/her action. But the first user's action should make the second user's action invalid. The problem is that the check occurs nearly simultaneously for each user.

+1  A: 

More detail about your specific problem would be helpful to get a good solution - however, it's sounds like you need some form of interprocess/cross-server locking. There's nothing directly within the .NET framework (or Win32 APIs) to make this easy - you have to roll your own solution, I'm afraid.

You may want to look into some sort of clustered queuing mechanism so that only one process/thread is executing an action. This may or may not be easy in your overall design and the problem you are trying to solve. Alternatively, you could use a central authority (like a database) and a locking structure to determine if a lock for a particular action has already been started. The problem there is it's hard to make such a solution scale well due to the need to constantly interact with the database.

Another option you may have is to allow multiple process to attempt to process the same action simultaneously but to only allow one to complete. This can be tricky to ensure - but it's less expensive (computationally) to perform extra work and throw it away than to constantly check if someone else is already doing the work.

LBushkin
+1  A: 

It sounds like you have a bad design. Your service should not maintain state at all, if possible. That way, there would be no shared state to step on.

If you must maintain state, then you must interlock all access to that shared state. You can use the "lock" keyword in C# for this:

private static object _stateLocker = new object();
private static int _someSharedState = 0;

public void SomeAction()
{
    lock (_stateLocker)
    {
        _someSharedState ++;
    }
}

public int GetValue()
{
    lock (_stateLocker)
    {
        return _someSharedState;    }
}
John Saunders
The state is really only maintained in the database. The validation checks for an action occur in the service. It's more about ensuring that a set of actions is atomic rather than access to shared state. I agree that locking would solve the problem, except for when the server is also clustered.
Shane Fulmer
@Shane: then you need transactions around your database state changes. That would work even across a cluster, assuming a shared database.
John Saunders
I understand transactions at a high level, but not as in depth as I should. What would something like that look like from C#? Does the TransactionScope object handle this situation?
Shane Fulmer