Used to control access to resources in a multithreaded environment.
NumResources As Integer
Constructor(NumResources as Integer)
The Semaphore has a constructor that takes the initial count of the number of resources the Semaphore is protecting as an optional parameter. This defaults to 1. If you need to manage access to a single resource, you can instead use a CriticalSection.
Call Release to give a locked resource back to the Semaphore. You must call Release when you are finished using a locked resource in order to make it available to other requests.
Call Signal to obtain a lock on a resource. Once you are done with the shared resource, the thread should call Release to increment the internal counter.
Every time thread calls Signal, the Semaphore decrements the counter. If the counter is less than zero, it suspends the thread.
When you obtain a lock, you can use the resource without fear that another thread will try to use it simultaneously. If the call succeeds, this function returns immediately and you code continues to execute. If the lock is not available, then the thread that called this method will wait until the lock becomes available. When the call returns, you will have the lock, but you may have to wait until the lock becomes available. When you are finished using the resource, call the Release method to give it back to the Semaphore.
TrySignal As Boolean
This is a more friendly version of the Signal method that gives you a sneak-peek to determine whether there is a lock available.
If there is a lock available, you are granted the lock and TrySignal returns True. When you are finished with the resource, call Release to give it back to the Semaphore. If the lock is not available, you do not wait for it. Instead, TrySignal returns False to let you know. Do not attempt to use the resource after it returns False because you are likely to collide with another thread.
This example tests whether the lock is available before trying to use the resource.
// Want to make sure that only the right thread // gets in here. One at a time! If mLock.TrySignal Then // Now that we're here, we can change the resource SharedResource.Value = value AccessText.Text = id.ToString // And now that we've done something with the // resource, we want to release our lock on it mLock.Release End If
A Semaphore is an object that can be used to coordinate access to a shared resource.
To acquire the ownership of a Semaphore, a thread calls the Signal or TrySignal methods. If the Semaphore isn't owned, the thread acquires ownership, which means you have a lock on it. Otherwise the thread is forced to wait until the Semaphore is released via the Release method by the owning thread.
Every time you successfully obtain an ownership lock on the resource, the Semaphore will decrement its internal count of available resources. When there are no more resources, threads that request ownership locks will begin to block and wait for resources. This is why you can specify the initial count of resources -- to give you more control over the behavior of the Semaphore.
The Semaphore class is different from the CriticalSection and Mutex classes in this way: calling Signal in the same thread will cause the counter to decrement. If you call Signal recursively, you will cause the application to hang.
This example uses a Semaphore to ensure that only one thread at a time writes to a file.
Add a public property to the App class:
FileAccess As Semaphore
And in the Opening event handler, initialize it:
// Allow only a single thread to access the file at a time FileAccess = New Semaphore(1)
In the thread, check the FileAccess Semaphore to see if you can write to the file:
// This will Suspend this thread if another has the lock // When it is released, this thread will continue to run App.FileAccess.Signal // Now you can open the file for writing WriteDataToFile // Call your code here // When you are finished, release the semaphore App.FileAccess.Release
All project types on all supported operating systems.