So with the new preemptive threads, I’m learning all about Semaphores.
According to the documentation, a Semaphore can protect multiple resources. So let’s say you have 3 resources you want to protect when running a preemptive thread, you would call
MySempahore = New Semaphore(3)
OK, and then when you hit the first resource you want to protect you would call:
MySemaphore.Signal
And you would do the same with the second resource, etc.
But - how does the app now WHAT resource is being protected if the same semaphore is protecting multiple items? Let’s say I do this. I have 3 resources allocated for my semaphore. I have protected an object in the thread and let’s say that is resource number 2. So the Semaphore has one resource left.
Now let’s say I am doing a main thread operation and I call MySemaphore.Signal (this should success as I have one resource left) and try to then access that second object that is currently protected in the thread. What happens? I have a resource that is protected that I am trying to use but it’s now “protected” by two different semaphore calls. What happens?
Semaphores are typically for protecting one or more of the same resource.
Think of your local big-box hardware store where they rent out cement mixers. They have four of them available to rent. In the aftermath of hurricane Helene, hundreds of people need a cement mixer. The store sets up a semaphore (or waiting list) for the cement mixer.
When a customer comes in, if they want a cement mixer and are willing to stand there and wait if one is not available, they call Signal. If a mixer is available, they get it and the number available decreases by one. If not, they have to wait.
If on the other hand they’re not willing to wait, they can call TrySignal. In that case, if a mixer is available, they get it immediately. Otherwise they can come back another day.
In all cases, once the person is done with the mixer, they need to return it to the store, making it available for the next person by calling the Release method.
But here’s the thing - there’s nothing tying a Semaphore to a specific object or resource. If I have an object, say a dictionary that I want to protect, then before executing the code that uses that dictionary I would call Semaphore.signal. No problem. But I may use 5 other objects in that same block of code. The way I understand it, then all those objects are held and locked as well - correct? So a single semaphore can put a lock on multiple resources. So you can’t really say it’s one or more of the same resource. And that I don’t understand either.
So taking your cement mixer examples. In code I would have the cement mixers stored as an Array or in a dictionary. I would call Semaphore.Signal before accessing either the array or the dictionary, so that really locks up all the cement mixers at once. I supposed I could have properties assigned as CementMixer1, CementMixer2, etc. But an array or dictionary is a much more efficient way of storing multiples of the same resource. And I would call it iffy to wait until extracting one of those resources from the dictionary or array because the code blocks could potentially modify the structure of the arrays or dictionaries. So I would think you would want to protect the whole thing. Am I missing something here?
So going back to my original question - if I have a semaphore with multiple resources available, and I have called the signal method twice in my thread and then I call for the third signal in the main thread - what happens when I try to then access one of the resources that I had previously protected with signal calls inside the thread? I would assume that you still can’t access them but then does the signal call fail or what happens? And what happens if after calling signal on the main thread, then suddenly one of those resources is released from the preemptive thread? Is it now protected on the main thread?
And one more question - Does the Semaphore need to be released from the thread where Signal was called? Or can you release it from anywhere?
So sayI have resources tied up in a thread and have semaphores active. Let’s say I want to just stop that thread immediately. So from the main thread I call MyThread.stop. Now can I then can I call release on all potential semaphores that had been signaled in the thread?
No, a Semaphore should only be used to protect a single resource. The fact that you can do Semaphore(3) just means that the Semaphore will allow up to three simultaneous uses of the resource.
If you are operating in a preemptive threading model, it’s very likely that you only want one use of a protected resource at a time.
This whole business only works if each thread which is going to do something with a resource, obeys the rules and tries to acquire the semaphore that you assign for that resource. And the thread must release the semaphore when it has finished messing with teh resource. That way the usage of the resource is properly serialised.
Edit: nothing stops any thread accessing a resource whether it has acquired the corresponding semaphore or not. But the situation is that all threads have to play nice and follow the rules.
OK. So this is very confusing. If the purpose of a Semaphore is to protect a resource from being clobbered by another thread, then how is allowing simultaneous uses of that resource going to protect anything?
Second, how can you protect just one resource with a semaphore? How does it know what resource to protect?
Let’s say I have a window with objects Foo and Bar. Let’s say I have a preemptive thread that runs and manipulates Foo and Bar but the main thread also accesses them to read their values.
So I am manipulating both of these in the thread code. If I have two different semaphores, FooSemaphore and BarSemaphore, how does the framework know which object I want to protect?
There isn’t simultaneous use. The first thread acquires the sempahore and continues and uses the resource. The second (assuming a count of 1) tries to acquire the sempahore because it too wants to use the resource. But it can’t get it, and that thread is suspended until such time as the first thread releases the semphore. The second thread is then resumed and now owns the semaphore.
A semaphore knows nothing about a resource. The association betwen the two is a matter for YOU to define and decide upon when writing the code. I have a resource named wiggy and I decide that a semaphore called nippy will protect that one. It’s then up to me as programmer to follow that association and write all my code so that no thread tries to access wiggy unless it owns nippy.
The purpose of a semaphore is to control an access queue, a flux, to some resource. A critical section is like a semaphore for 1 accessor only, very useful to block something, do something fast, and release without clashing operations on that thing.
Actually one thing that surprises me a little with the business of a semaphore (with count) protecting more than one instance of a resource, is that the semaphore isn’t returning a reference to the instance being protected. If a semaphore has a count of say five and the association decided by me is between this sempahore (5) and an array of some resource (also 5), then I’d need to know, on successful acquisition of the resource, which one I can use.
Edit - should have said (for greater clarity):
… then I’d need to know, on successful acquisition of the semaphore, which instance of the resource I can use.
They are like real semaphores on the streets with 2 lights, green and red. Your code stops running when finding it red ( in the .Enter() ), and resumes when it becomes green. It becomes green when another “car” said it left (.Leave() ) that zone (using a count of 1). That Critical Section.
It’s used very much like a Transaction lock in SQL to assure something “atomic” is done correctly.
There’s clearly a lot of confusion here about how to use Semaphores. Let me try to put together some concrete examples.
Controlling Access to a Pool of Resources
Let’s say you have three physical robot arms controlled by your app - represented by a class RobotArm in code. Obviously you can’t have multiple threads trying to control an arm at the same time - the commands might overlap and cause safety issues or damage - so you only allow the code to request access to an arm - the code can’t create RobotArm classes on its own.
Pseudocode:
Class RobotArmPool
Private property AllArms() as RobotArm
Private property ArmAccessSemaphore as Semaphore
Private property ArmsInUse as Dictionary
Method Constructor()
// We have three arms available to control
ArmAccessSemaphore = New Semaphore(3)
AllArms.Add New RobotArm("192.168.0.20")
AllArms.Add New RobotArm("192.168.0.24")
AllArms.Add New RobotArm("192.168.0.51")
// This will keep track of which arms are in use
ArmsInUse = New Dictionary
End
Function AcquireArmAccess() as RobotArm
// Signal the semaphore
// This will pause the calling thread if the arm limit has been reached
ArmAccessSemaphore.Signal
// Find an arm that is available for use and return a reference
For each CurrentArm as RobotArm in AllArms
If Not(ArmsInUse.HasKey(CurrentArm)) then
ArmsInUse.Value(CurrentArm)=True
Return CurrentArm
End
Next
End
Function ReleaseArmAccess(theArm as RobotArm)
// If we find that this arm is in use, mark it as free and release the semaphore
If ArmsInUse.HasKey(theArm) then
ArmsInUse.Remove(theArm)
// If any threads are waiting on arm access, this Release will permit them to continue
ArmAccessSemaphore.Release
End
Next
Controlling Access to Functionality
In a preemtive threading scenario, you may need to guarantee that a piece of code is never accessed simultaneously by two threads. For example, you may be logging events to a file and if two threads wrote to the file at the same time, you’d get garbled entries. You want to make sure that each write completes before the next one happens.
Pseudocode:
Class LogFileWriter
Private property WriteSemaphore as Semaphore
Private property OutputStream as TextOutputStream
Method Constructor(theOutputStream)
me.OutputStream = theOutputStream
me.WriteSemaphore = New Semaphore
End
Method WriteLogItem(theText as String)
//Signal the semaphore that we are about to use this section of code
//Once we signal, the calling thread has exclusive access
//Any other thread will be paused right here until the Semaphore is released
WriteSemaphore.Signal
//Do the writing
me.OutputStream.WriteLine(theText)
//Release the semaphore
//If one or more threads are paused on this semaphore, one of them will be permitted to continue
WriteSemaphore.Release
End
Isn’t the code re-entrant? Surely you just pass the code a reference to the arm in question - it can then do the lookup to find its IP address and connect to it, send it commands, etc.
The whole idea is that controlling a robot arm is intrinsically not reentrant. The arm might be welding a part on a car, or performing a series of steps that can’t be interrupted. That’s why we’ve put code in place to make sure that only one piece of code has access to the arm to send it commands.