Opened 6 years ago

#12476 new Bugs

Using named_condition_any with a readers-writer lock

Reported by: Chris Evans <chris.evans@…> Owned by: Ion Gaztañaga
Milestone: To Be Determined Component: interprocess
Version: Boost 1.58.0 Severity: Problem
Keywords: interprocess named_condition_any Cc:

Description

I am trying to use condition variables to signify updated data in a managed_shared_memory segment. I have one "writer" and multiple "readers" of the shared state, so I am using a readers-writer lock.

Unfortunately, although the code compiles, the reader processes are never awakened from wait() and block forever.

It seems named_condition_any may be incompatible with named_sharable_mutex, scoped_lock, sharable_lock, or some combination of the three. Attached is a producer and consumer process that demonstrates the behavior. Run the producer first, then run the consumer.

Expected behavior: consumer process will print values for "copy of int" every 2 seconds (as producer updates)

Observed behavior: consumer process blocks on named_condition_any::wait() and never awakens.

Including the code here in case the attachments don't go through:

PRODUCER:

#include <thread>
#include <chrono>
#include <iostream>

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_sharable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/named_condition_any.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace bi = boost::interprocess;
using SharedMutex           = bi::named_sharable_mutex;
using ReadLock              = bi::sharable_lock<SharedMutex>;
using WriteLock             = bi::scoped_lock<SharedMutex>;
using NewEntryCondition     = bi::named_condition_any;

constexpr char SHM_NAME[]       = "shared_mem";
constexpr char MUT_NAME[]       = "shm_mut";
constexpr char COND_NAME[]      = "shm_cond";
constexpr char CUR_INT_NAME[]   = "shm_int";


int main(int argc, char *argv[])
{
    // Remove the shared mem, condition variable, mutex
    struct shm_remove
    {
        shm_remove() { bi::shared_memory_object::remove( SHM_NAME ); }
        ~shm_remove() { bi::shared_memory_object::remove( SHM_NAME ); }
    } remover;
    struct mut_remove
    {
        mut_remove() { SharedMutex::remove(MUT_NAME); }
        ~mut_remove() { SharedMutex::remove(MUT_NAME); }
    } mut_remover;

    struct cond_remove
    {
        cond_remove() { NewEntryCondition::remove(COND_NAME); }
        ~cond_remove() { NewEntryCondition::remove(COND_NAME); }
    } cond_remover;

    // Create the shared mem, condition variable, mutex
    bi::managed_shared_memory segment(bi::create_only, SHM_NAME, 2*65536);
    SharedMutex         sh_mut(bi::create_only, MUT_NAME);
    NewEntryCondition   sh_cond(bi::create_only, COND_NAME);

    int& shared_int = *segment.construct<int>("shared_int")(0);

    for (int i=0;;i++) {
        std::this_thread::sleep_for(std::chrono::seconds(2));

        {
            WriteLock w_lock( sh_mut );

            shared_int = i;
            std::cout << "set shared_int to: " << shared_int << std::endl;

            sh_cond.notify_all();
        }

    }



    return 0;
}

CONSUMER:

#include <thread>
#include <chrono>
#include <iostream>

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_sharable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/named_condition_any.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace bi = boost::interprocess;
using SharedMutex           = bi::named_sharable_mutex;
using ReadLock              = bi::sharable_lock<SharedMutex>;
using WriteLock             = bi::scoped_lock<SharedMutex>;
using NewEntryCondition     = bi::named_condition_any;

constexpr char SHM_NAME[]       = "shared_mem";
constexpr char MUT_NAME[]       = "shm_mut";
constexpr char COND_NAME[]      = "shm_cond";
constexpr char CUR_INT_NAME[]   = "shm_int";


int main(int argc, char *argv[])
{
    // Open the shared mem, condition variable, mutex
    bi::managed_shared_memory segment(bi::open_only, SHM_NAME);
    SharedMutex         sh_mut(bi::open_only, MUT_NAME);
    NewEntryCondition   sh_cond(bi::open_only, COND_NAME);

    int& shared_int = *segment.find<int>("shared_int").first;
    int  copy_of_int = -1;

    for (int i=0;;i++) {
        {
            ReadLock r_lock( sh_mut );

            std::cout << "calling named_condition_any::wait()" << std::endl;
            sh_cond.wait(
                    r_lock,
                    [&shared_int, &copy_of_int]() {
                        std::cout << "checking predicate..." << std::endl;
                        return (copy_of_int < shared_int);
                    });

            copy_of_int = shared_int;
            std::cout << "copy of int = " << copy_of_int << std::endl;
        }

    }

    return 0;
}

Attachments (3)

producer.cpp (2.0 KB ) - added by Chris Evans <chris.evans@…> 6 years ago.
consumer.cpp (1.7 KB ) - added by Chris Evans <chris.evans@…> 6 years ago.
CMakeLists.txt (896 bytes ) - added by Chris Evans <chris.evans@…> 6 years ago.

Download all attachments as: .zip

Change History (3)

by Chris Evans <chris.evans@…>, 6 years ago

Attachment: producer.cpp added

by Chris Evans <chris.evans@…>, 6 years ago

Attachment: consumer.cpp added

by Chris Evans <chris.evans@…>, 6 years ago

Attachment: CMakeLists.txt added
Note: See TracTickets for help on using tickets.