3

I have a web application written in C# which uses external dll written in C++. Communication between clients (web browsers) and a web application is done using SignalR. For communication between web application and the dll I am using a class and I create an instance of this class for every connected client. Instance of this class is stored in static list - it is shared between requests.

When a request is issued I fetch a connector (class to communicate with dll) from a list and then call a method which can take any time between 0.1 seconds and 3 seconds.

Beside that I have a job which is triggered every minute (using Hangfire) which loops through the list and disposes connectors which are inactive for certain time. Disposing connector can also take around 1 or 2 seconds.

Because application is multithreaded I am using a shared lock between the connector class and the job which disposes connector. Using the lock I avoid that connector is disposed between fetching the connector and calling the method.

In "pseudo-code" this would look like:

object globalLock = new object();


-- signalr hub method
public void HubMethod(string sessionId, string param) {
  lock (globalLock) {
    DllConnector connector = GetConnector(sessionId);
    connector.CallMethod(param);
  }
}


-- hangfire job
public void KillInactive() {
  lock (globalLock) {
    foreach (DllConnector connector in listOfConnectors) {
      if (connector.IsInactive()) {
         listOfConnectors.Remove(connector);
         connector.Dispose();
      }
    }
  }
}

Question:

Because I am expecting "large" number of concurrent clients (requests) I am afraid that this won't scale - requests and the job will became unresponsive. How can I avoid this - to minimize waiting for the lock and to avoid disposed connectors between fetching and calling the method. Are there any patterns?

  • 1
    Is there any risk of two threads simultaneously needing a connector for the same sessionID? – Brian Nov 29 '15 at 0:34
  • Check out immutable collections. – Johan Larsson Dec 15 '15 at 23:38
  • Where and how are you creating new connectors? Is it in a GetConnector method? Show us! – Euphoric Dec 16 '15 at 7:37
1

The way these things are normally done is with threadpools. See System.Threading.ThreadPool and read MSDN: How to: Use a Thread Pool

Also, the modern approach to sharing data in multithreaded environments is to avoid using locks and to use message-passing instead. This results in systems that are testable, and that once they are known to work, they tend to keep working without nasty surprises due to rare timing issues.

Note: invoking listOfConnectors.Remove( x ); within a foreach( var x in listOfConnectors ) will throw a 'collection was modified' exception.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.