3

I have a list of Dinosaur objects, that can be added to, removed from, and the dinosaurs themselves need to be fed. This all happens in a highly multi-threaded environment, so the list is mutex protected.

static Mutex s_dinosaurMutex;
static vector<Dinosaur> s_dinosaurList;

void AddDinosaur(const Dinosaur& dinosaur)
{
    s_dinosaurMutex.Lock();
    s_dinosaurList.push_back(dinosaur);
    s_dinosaurMutex.Unlock();
}

void RemoveDinosaur(const Dinosaur& dinosaur)
{
    s_dinosaurMutex.Lock();

    vector<IMadderReceiver*>::iterator it = find(s_dinosaurList.begin(), s_dinosaurList.end(), dinosaur);
    if (it != s_dinosaurList.end())
        s_dinosaurList.erase(it);

    s_dinosaurMutex.Unlock();
}

void FeedDinosaur(const Dinosaur& dinosaur)
{
    s_dinosaurMutex.Lock();

    vector<IMadderReceiver*>::iterator it = find(s_dinosaurList.begin(), s_dinosaurList.end(), dinosaur);
    if (it != s_dinosaurList.end())
        (*it).Feed(); // Feeding a dinosaur can take a long time, ~ 1 second

    s_dinosaurMutex.Unlock();
}

Now the problem is in the feeding. This can take a long time, but it's absolutely fine if multiple threads feed the same (or a different) dinosaurs at the same time. The feeding process should therefore not stall other FeedDinosaur calls, though it should stall for Add and Remove calls, and wait for those to finish. The behaviour at the moment is that many threads are lining up queuing in order to Feed the dinosaurs, which makes the system grind to a hold.

Is there a particular (mutex-like) design patterns that allows this type of behaviour of ok-ing threads that require read-only access?

Yellow
  • 3,955
  • 6
  • 45
  • 74
  • 1
    Yes, this is what a "readers-writer lock" is for. – Sneftel Jul 06 '15 at 14:25
  • 1
    In addition to what @Sneftel mentioned, I would also recommend using an RAII wrapper around your mutex like `std::lock_guard` to ensure that the mutex is released on every exit path of your functions – Alejandro Jul 06 '15 at 14:35
  • possible duplicate of [Reader/Writer Locks in C++](http://stackoverflow.com/questions/244316/reader-writer-locks-in-c) – ecatmur Jul 06 '15 at 15:17

1 Answers1

5

This is a reader-writer mutex; Boost and C++ use the more general term "shared mutex" because it can be used for patterns other than multiple reader-single writer.

Boost.Thread has shared_mutex since version 1.35.0 (Reader/Writer Locks in C++). C++ has shared_timed_mutex since C++14 and will have shared_mutex in C++17; until that is available you can use C++14 shared_timed_mutex and just not use the timeout mechanism.

In your writer thread, lock the shared mutex for unique access (use a unique_lock); in your reader threads, lock the shared mutex for shared access (use a shared_lock).

Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • Excellent answer, thank you. Does there happen to be a C++11 alternative, apart from using Boost? – Yellow Jul 06 '15 at 15:50
  • 1
    @Yellow it'd be difficult to implement correctly and efficiently - see http://stackoverflow.com/questions/12033188/how-would-a-readers-writer-lock-be-implemented-in-c11 – ecatmur Jul 06 '15 at 16:18