Semaphore-type class for thread safety. More...
Public Member Functions | |
BLocker () | |
Create a new BLocker with the default name "some BLocker" and benaphore-style locking. | |
BLocker (bool benaphoreStyle) | |
Creates a BLocker with the default name "some BLocker" and the given locking style. | |
BLocker (const char *name) | |
Creates a new BLocker with the given name and benaphore-style locking. | |
BLocker (const char *name, bool benaphoreStyle) | |
Creates a new BLocker with the given name and locking style. | |
virtual | ~BLocker () |
Destructor. | |
int32 | CountLockRequests () const |
Return the number of threads with a pending lock request. | |
int32 | CountLocks () const |
Return the number of recursive locks that are currently held. | |
status_t | InitCheck () const |
Check whether the locker has properly initialized. | |
bool | IsLocked () const |
Check if the calling thread is actually holding the lock. | |
bool | Lock () |
Add a lock request and block on it until we get it. | |
thread_id | LockingThread () const |
Return the thread_id of the thread that's currently holding the lock. | |
status_t | LockWithTimeout (bigtime_t timeout) |
Add a lock request and block until we get it or until it times out. | |
sem_id | Sem () const |
Return the sem_id of the semaphore this object holds. | |
void | Unlock () |
Release the lock that's currently held. | |
Semaphore-type class for thread safety.
The BLocker interface is not merely a wrapper around a semaphore, but it also has two advantages. First of all, it implements a benaphore. A benaphore is in some ways more speed efficient, because before it uses the internal semaphore, it first checks against a variable that is only operated on with atomic operations. Setting a variable is a lot more efficient than acquiring a semaphore, thus this type of locking is much preferred.
It basically works as follows. Whenever you newly created BLocker object receives a locking request, it atomically sets the benaphore variable to 1
. Then only additional calls from different threads will utilize the semaphore. You can imagine that in many cases where you protect of data that might be accessed by two or more concurrent threads, but the chances of it happening being very small, the benaphore benefits the most from its speed.
The other feature of BLocker that improves basic semaphore handling is that it allows for recursive locks. The following piece of code works with a BLocker, but block inevitably with a semaphore. Let's pretend I call Water()
:
This code would work because BLocker keeps track of the amount of lock requests from the same thread. A normal semaphore would block in Grow()
because the semaphore would be acquired already. Please do make sure you pair every Lock() with an Unlock() though, or you'll create a deadlock.
BLocker::BLocker | ( | ) |
Create a new BLocker with the default name "some BLocker" and benaphore-style locking.
This BLocker will use the benaphore-style locking.
BLocker::BLocker | ( | const char * | name | ) |
Creates a new BLocker with the given name and benaphore-style locking.
name | A NULL-terminated string that contains the name of the semaphore. Note that the length of the names are limited to B_OS_NAME_LENGTH constant, which includes the \0 character. |
BLocker::BLocker | ( | bool | benaphoreStyle | ) |
Creates a BLocker with the default name "some BLocker" and the given locking style.
benaphoreStyle | If you pass true , the locker will be in benaphore style (which is the default option for other constructors). If you pass false , the object will completely rely on semaphores for its functioning. |
BLocker::BLocker | ( | const char * | name, |
bool | benaphoreStyle | ||
) |
Creates a new BLocker with the given name and locking style.
name | A NULL-terminated string that contains the name of the semaphore. Note that the length of the names are limited to B_OS_NAME_LENGTH constant, which includes the \0 character. |
benaphoreStyle | If you pass true , the locker will be in benaphore style (which is the default option for other constructors). If you pass false , the object will completely rely on semaphores for its functioning. |
|
virtual |
Destructor.
Release the internal semaphore. Because of this, any pending Lock() calls from other threads be cancelled. The return code will be false
for those calls.
int32 BLocker::CountLockRequests | ( | void | ) | const |
Return the number of threads with a pending lock request.
int32 BLocker::CountLocks | ( | void | ) | const |
Return the number of recursive locks that are currently held.
status_t BLocker::InitCheck | ( | ) | const |
Check whether the locker has properly initialized.
B_OK
if the semaphore has been properly initialized or any other error (negative) value related to semaphore initialization.bool BLocker::IsLocked | ( | void | ) | const |
Check if the calling thread is actually holding the lock.
true | The thread from which this method is called from is currently holding the lock. |
false | The object is unlocked or the lock is held by another thread. |
bool BLocker::Lock | ( | ) |
Add a lock request and block on it until we get it.
true | Lock acquired successfully. |
false | Failed to acquire the lock. Most probable cause is that the object is deleted. This frees the semaphore and releases the pending Lock() requests. |
Referenced by BAutolock::Lock().
thread_id BLocker::LockingThread | ( | void | ) | const |
Return the thread_id
of the thread that's currently holding the lock.
sem_id BLocker::Sem | ( | void | ) | const |
Return the sem_id of the semaphore this object holds.
void BLocker::Unlock | ( | void | ) |