Problem: I need to write a function which returns a value for a input key from a map. If function can’t found the value in map it will fetch the value from database, write into map for future use and return the same. There can be multiple threads calling this function.
I am thinking on this line:
string GetData (const int key)
{
pthread_rwlock_rdlock(&rwlock); //read lock
string result = "not found";
my_map::const_iterator iter = m.find(key);
if ( iter != m.end() )//found
{
result = iter->second;
}
else //missing
{
pthread_rwlock_wrlock(&rwlock); // write lock
//fetch value from data base
//if successful, add to the map
m[key] = "missing data";
result = "missing data";
pthread_rwlock_unlock(&rwlock); // unlock write lock
}
pthread_rwlock_unlock(&rwlock); // unlock read lock
return result;
}
Is this function thread safe? Isn’t it possible for two or more threads to queue up on write lock and query the same key from database? If yes, how can I avoid that scenario?
This function is not thread-safe because it results in undefined behavior. When you attempt to obtain the write lock, you already hold a read lock. From the documentation for
pthread_rwlock_wrlock:This solution is also not exception-safe. If an exception is thrown while the lock is held, the lock will not be released and your application will undoubtedly deadlock. You should use a C++ threading library (Boost.Thread, OpenThreads, just::thread, or something similar) that provides a C++-oriented design supporting things like
scoped_lock(orlock_guard).As for making the algorithm correct, you need something along the lines of:
[If you use some sort of
lock_guard, you don’t need to worry about releasing held locks when you return]