While reading about thread constructs, I’ve come across this advice more than once: “don’t try to write your own”.
I accept that recommendation. I don’t have any thread needs that can’t be satisfied by existing code. But, they need to be wrapped up to better fit what I’m trying to do.
Here are 2 examples
Start / Stop
There are a lot of objects in the app server with start/stop methods. These methods need to be thread safe, and need to defend against misuse. IE: if you call START twice, that’s useless. You can’t actually start it again.
Back when I was a boy, I was in the same situation, and I solved it by creating a base class that had start/stop methods. Those methods would handle the locking and prevent multiple calls. The subclasses implemented protected methods OnStart and OnStop.
That was functional, but these years later i’m not a fan. Of course there is a single inheritance which could be a problem. But, really, the object hierarchy isn’t in support of an IS relationship. It’s more convenience.
The solution for this is a class called StartStop. It is used here:
You pass the start and stop methods an Action. If it is appropriate to call the action, it will. Otherwise, it does not.
The innards of StartStop makes sure that you don’t start something that is already started, or stop something that is already stopped. Additionally, it only lets one thread do it. Other threads are kicked out as soon as possible.
Other variations could be implemented as needed. For example: perhaps you would prefer it to throw an InvalidOperationException? We have the technology.
Internally, it uses a LOCK statement (with quick exit), and a boolean to keep track of if it is currently started.
I’ve seen some really offensive uses of LOCK. More than once, if there was a theading issue, I’ve seen people put in a lock statement not realizing the potential impact.
The applications class manages a bunch of applications (hence the clever class name). Each start/stop has to be. thread safe. You can’t start and stop the TEST application at the same time, nor can you start it twice at the same time. If you just toss in a LOCK (THIS.STARTSTOPLOCK), then you’re blocking all operations for all apps rather than just the app you need.
So, instead, you have a lock object per application. Then you need to keep track of the lock objects per app. That stuff is all built in. But, do you want to code that 12 times?
I wrapped that up into a class called SingleThread. This is how it’s used in the Applications class.
You give it a key and an Action. If the key isn’t already known, then the action is executed. Otherwise, it gets out. The key is constructed from the application name.
The name of the method is ExecuteNoBlock. If it can’t execute, it just exits. (Not shown: it returns false if it doesn’t execute, true if it does execute.)
I’m using this class in several places now. It’s helpful.
Internally, nothing fancy: it’s using a concurrent dictionary. If it can add the key to the dictionary, then it executes. If it can’t, then it exits. Sweet. After the execute, the item is removed from the dictionary. The dictionary doesn’t have a value; just using a 0 byte. We really only care about existence or non-existence. (Perhaps there is a more appropriate concurrent collection?)
Here’s the entire SingleThread class: