I want to use a shared mutex so threads only get locked when a vector/map/whatever is written to rather than read from. But I think func2() will never get the uniqueue lock because func1() will never get to unlock. Is there any way to not count a same-thread lock on shared_mutex when trying to get the uniqueue lock? Or would the problem still occur even then?
I'm guessing I need to find a way to force-get the lock (one thread at a time) once all threads have reached func2() OR have released the lock.
func2()
{
boost::unique_lock<boost::shared_mutex> lock_access3(shared_mutex);
/*stuff*/
lock_access3.unlock();
}
func1()
{
boost::shared_lock<boost::shared_mutex> lock_access1(shared_mutex);
func2();
lock_access1.unlock();
}
I believe you need to use a recursive mutex. See the good discussion on this question:
Recursive Lock (Mutex) vs Non-Recursive Lock (Mutex)
Boost provides this in the boost:recursive_mutex class.
Two things you need to do:
1) Since func1 implements a write operation, it needs to acquire an exclusive lock, not a shared lock.
2) Since func2 is called with the lock already held, it should not try to acquire the lock.
Related
I guess I'm a little unsure of how mutexs work. If a mutex gets locked after some conditional, will it only lock out threads that meet that same condition, or will it lock out all threads regardless until the mutex is unlocked?
Ex:
if (someBoolean)
pthread_mutex_lock(& mut);
someFunction();
pthread_mutex_unlock(& mut);
Will all threads be stopped from running someFunction();, or just those threads that pass through the if-statement?
You need to call pthread_mutex_lock() in order for a thread to be locked. If you call pthread_mutex lock in thread A, but not in thread B, thread B does not get locked (and you have likely defeated the purpose of mutual exclusion in your code, as it's only useful if every thread follows the same locking protocol to protect your code).
The code in question has a few issues outlined below:
if (someBoolean) //if someBoolean is shared among threads, you need to lock
//access to this variable as well.
pthread_mutex_lock(& mut);
someFunction(); //now you have some threads calling someFunction() with the lock
//held, and some calling it without the lock held, which
//defeats the purpose of mutual exclusion.
pthread_mutex_unlock(& mut); //If you did not lock the *mut* above, you must not
//attempt to unlock it.
Will all threads be stopped from running someFunction();, or just those threads that pass through the if-statement?
Only the threads for which someBoolean is true will obtain the lock. Therefore, only those threads will be prevented from calling someFunction() while someone else holds the same lock.
However, in the provided code, all threads will call pthread_mutex_unlock on the mutex, regardless of whether they actually locked it. For mutexes created with default parameters this constitutes undefined behavior and must be fixed.
In boost land on Mac OS, following code will deadlock itself:
boost::mutex m;
m.lock();
m.lock();
the same goes with
boost::mutex m;
boost::mutex::scoped_lock lock(m);
boost::mutex::scoped_lock lock(m);
in Windows land, the same thread can get a Win32 mutex as often as it wants, as long as the release count is the same. I need the exact behavior with a boost sync object.
What you need is a boost::recursive_mutex:
The recursive_mutex class uses a Recursive locking strategy, so attempts to recursively lock a recursive_mutex object succeed and an internal "lock count" is maintained. Attempts to unlock a recursive_mutex object by threads that don't own a lock on it result in undefined behavior.
Note that the boost::mutex:
The mutex class uses an Unspecified locking strategy, so attempts to recursively lock a mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform.
In Computer Science the recursive mutex is called Reentrant Mutex:
In computer science, a reentrant mutex is a mutual exclusion, recursive lock mechanism. In a reentrant mutex, the same thread can acquire the lock multiple times. However, the lock must be released the same number of times or else other threads will be unable to acquire the lock
try to use a recursive mutex : As boost::mutex is not recursive, we need to use its recursive version boost::recursive_mutex
I have a class that opens transactions, adds operations to a queue, then closes the transaction. Across the open->close lifetime I would like to employ a recursive mutex, so that only one thread can have a transaction open at any time. All other threads are blocked until the current transaction is ended.
class MyObject
{
void beginTransaction()
{
// acquire mutex
}
void endTransaction()
{
// release mutex
}
boost::recursive_mutex m_mutex;
}
I am having difficulty determining how I can use a recursive_mutex in this case, as the lock would exist longer than the scope of a single method. Can anyone suggest how I might apply locking here?
Boost (and the standard library) provide mutexes, which can be locked and unlocked, and locks, which lock mutexes in their constructor and unlocks them in their destructor. Locks are really just lightweight wrappers that are used to ensure a lock is released when leaving scope.
In your case, you would just use the mutex directly, without wrapping it in a lock.
You can call m_mutex.lock() in beginTransaction to lock the mutex, then m_mutex.unlock() in endTransaction to unlock the mutex. If another thread attempts to call m_mutex.lock() between calls, it will block until the mutex is unlocked by the owning thread in endTransaction
If I have the following code:
#include <boost/date_time.hpp>
#include <boost/thread.hpp>
boost::shared_mutex g_sharedMutex;
void reader()
{
boost::shared_lock<boost::shared_mutex> lock(g_sharedMutex);
boost::this_thread::sleep(boost::posix_time::seconds(10));
}
void makeReaders()
{
while (1)
{
boost::thread ar(reader);
boost::this_thread::sleep(boost::posix_time::seconds(3));
}
}
boost::thread mr(makeReaders);
boost::this_thread::sleep(boost::posix_time::seconds(5));
boost::unique_lock<boost::shared_mutex> lock(g_sharedMutex);
...
the unique lock will never be acquired, because there are always going to be readers. I want a unique_lock that, when it starts waiting, prevents any new read locks from gaining access to the mutex (called a write-biased or write-preferred lock, based on my wiki searching). Is there a simple way to do this with boost? Or would I need to write my own?
Note that I won't comment on the win32 implementation because it's way more involved and I don't have the time to go through it in detail. That being said, it's interface is the same as the pthread implementation which means that the following answer should be equally valid.
The relevant pieces of the pthread implementation of boost::shared_mutex as of v1.51.0:
void lock_shared()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked)
{
shared_cond.wait(lk);
}
++state.shared_count;
}
void lock()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
exclusive_cond.wait(lk);
}
state.exclusive=true;
}
The while loop conditions are the most relevant part for you. For the lock_shared function (read lock), notice how the while loop will not terminate as long as there's a thread trying to acquire (state.exclusive_waiting_blocked) or already owns (state.exclusive) the lock. This essentially means that write locks have priority over read locks.
For the lock function (write lock), the while loop will not terminate as long as there's at least one thread that currently owns the read lock (state.shared_count) or another thread owns the write lock (state.exclusive). This essentially gives you the usual mutual exclusion guarantees.
As for deadlocks, well the read lock will always return as long as the write locks are guaranteed to be unlocked once they are acquired. As for the write lock, it's guaranteed to return as long as the read locks and the write locks are always guaranteed to be unlocked once acquired.
In case you're wondering, the state_change mutex is used to ensure that there's no concurrent calls to either of these functions. I'm not going to go through the unlock functions because they're a bit more involved. Feel free to look them over yourself, you have the source after all (boost/thread/pthread/shared_mutex.hpp) :)
All in all, this is pretty much a text book implementation and they've been extensively tested in a wide range of scenarios (libs/thread/test/test_shared_mutex.cpp and massive use across the industry). I wouldn't worry too much as long you use them idiomatically (no recursive locking and always lock using the RAII helpers). If you still don't trust the implementation, then you could write a randomized test that simulates whatever test case you're worried about and let it run overnight on hundreds of thread. That's usually a good way to tease out deadlocks.
Now why would you see that a read lock is acquired after a write lock is requested? Difficult to say without seeing the diagnostic code that you're using. Chances are that the read lock is acquired after your print statement (or whatever you're using) is completed and before state_change lock is acquired in the write thread.
I have a basic sample which needs review (C++).
Let's say I have a function PublicFunc(), and another one called PrivateFunc(). I'd like to synchronize them carefully. But PrivateFunc can sometimes call PublicFunc as well what means we are calling it from the same thread. This causes blocks, and I'd like to solve it.
mutable boost::mutex m;
void PublicFunc() {
m.lock();
//Here it blocks, but why?
//What I need is to get the lock if this func was called from PrivateFunc(), so exactly from the same thread.
//But! It should definitely block on calling PublicFunc from outside while we are for example in the 'OtherPrivateFunc'.
//Do some stuff
//this is not necessary
m.unlock();
}
void PrivateFunc() {
m.lock();
PublicFunc();
OtherPrivateFunc();
m.unlock();
}
Which mutex or lock is the right one from the boost library?
Thank you!
A mutex may only be locked once; any call to lock the mutex while it is locked will block, even if the attempt to lock the mutex is made by the thread that holds the lock on the mutex.
If you want to be able to lock a mutex multiple times on the same thread, use recursive_mutex.
Alternatively, consider reorganizing your code so that you have one set of (private) member functions that assume the mutex is locked, and have all other functions delegate to these. This can make the code clearer and can make it easier to verify that the synchronization is correct.