Question

I seem to be having an issue synchronizing a data collection. In this particular class, I have a data collection, mutex, and condition variable that looks something like:

map<std::string, double> collection;
boost::mutex collectionMutex;
boost::condition_variable collectionConditional;

For the most part, this works. However, recently I have added a function where I essentially assign a new value for each value in the collection. There's about 100-200 values in the collection, so not very many; all of the assignments happen very quickly. I've also made sure that no calculations occur during this step, it is merely a series of assignments. Surrounding the assignments, I have code that looks like this(based on an answer here on stackoverflow):

boost::mutex::scoped_lock lock(collectionMutex);
while(!lock.owns_lock())
{
    collectionConditional.wait(lock);
}
// Assignments here
collectionConditional.notify_one();

Elsewhere in the code, I have a function that 'reads' the information from the collection, and that looks something like this:

double result = 0;
boost::mutex::scoped_lock lock(collectionMutex);
while(!lock.owns_lock())
{
    collectionConditional.wait(lock);
}

result = collection["Some String"];

collectionConditional.notify_one();

What's happening is that when my 'write' function is called, it seems to deadlock for a while. It breaks out of it eventually so it's not a complete deadlock, but the waiting period can be a long time(several seconds). This should be something that's on the order of milliseconds or less.

The odd part is that I've successfully used the above writer function before and had multiple threads writing to this data collection without a problem. The reason I've made this change is a move to centralize the updates to this collection to one place, rather than having it be dependent on the run-time state of other threads.

Was it helpful?

Solution

Thanks to the comments on my question, I ended up doing several things:

  1. Stopped using operator[] in the read function and made the read function const.

  2. Stopped using the condition_variable

  3. Used shared_mutex based on the example in this other post.

The code:

map<std::string, double> collection;
mutable boost::shared_mutex collectionMutex;

...

//Write function:
void mapData()
{
    // get upgradable access
    boost::upgrade_lock<boost::shared_mutex> lock(collectionMutex);

    // get exclusive access
    boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);

    // Assignments here.  Eg:
    // collection["Some String"] = 0.0;
}

// Read function:
double readData(std::string name) const
{
    double result = 0;
    boost::shared_lock<boost::shared_mutex> lock(collectionMutex);
    map<std::string, double>::const_iterator it = collection.find(name);
    if(it != data.end())
    {
        result = it->second;
    }
    return result;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top