0

I do have to dive into concurrency with C++11 at the moment and I am having a very hard time to get a basic producer/consumer to work with Boost.Interprocess using shared memory. I've already tried a lot of different things, but I can't make two simple programs (1x producer, 1x consumer) work in a reliable manner, because they run into deadlocks.

I have the following requirements:

  1. The example shall work regardless of the order of process execution. It should not make a functional difference if either consumer or producer is started first.

    Note: For this reason I'm using boost::interprocess::open_or_create in both processes (maybe that cause problems too).

  2. The producer shall construct a shared memory object (in this case an int) if notified by the consumer.
  3. The consumer shall read the shared memory object if notified by the producer, print the read data and destroy the shared memory object.
  4. Each process shall not "poll", but block/wait until it is allowed to do work (the allowance comes from the other process).

Here is my current C++ code which causes a deadlock without producing and/or consuming even one object. After looking a long time at the code, I'm not be able to see the forest for the trees.

producer.cpp

// Standard Library
#include <iostream>
#include <thread>

// Boost.Interprocess
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>

int main() {
  std::cout << "Started Producer" << std::endl;

  try {
    std::cout << "Producer: Open/Create shared memory segment" << std::endl;
    boost::interprocess::managed_shared_memory managed_shm{
        boost::interprocess::open_or_create, "SharedMemory_Segment", 1024};
    std::cout << "Producer: Open/Create mutex" << std::endl;
    boost::interprocess::named_mutex mutex{boost::interprocess::open_or_create,
                                           "SharedMemory_Mutex"};
    std::cout << "Producer: Open/Create condition" << std::endl;
    boost::interprocess::named_condition condition_read{
        boost::interprocess::open_or_create, "SharedMemory_ConditionRead"};
    boost::interprocess::named_condition condition_write{
        boost::interprocess::open_or_create, "SharedMemory_ConditionWrite"};

    std::cout << "Producer: Start work" << std::endl;
    for (int i = 0; i < 10; ++i) {
      std::cout << "Producer: Try to get the lock for the shared mutex "
                   "(potential blocking)"
                << std::endl;
      boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock{
          mutex};

      std::cout << "Producer: Wait for Consumer" << std::endl;
      condition_read.wait(lock);

      std::cout << "Producer: Construct data" << std::endl;
      managed_shm.construct<int>("SharedMemory_Data")(i);

      std::cout << "Producer: Unlock the mutex" << std::endl;
      lock.unlock();

      std::cout << "Producer: Notify Consumer" << std::endl;
      condition_write.notify_one();
    }
  } catch (const boost::interprocess::interprocess_exception& ex) {
    std::cerr << "boost::interprocess::interprocess_exception: " << ex.what()
              << std::endl;
  } catch (const std::exception& ex) {
    std::cerr << "std::exception: " << ex.what() << std::endl;
  } catch (...) {
    std::cerr << "unhandled exception\n";
  }
}

consumer.cpp

// Standard Library
#include <iostream>
#include <thread>
#include <utility>

// Boost.Interprocess
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>

int main() {
  std::cout << "Started Consumer" << std::endl;

  try {
    std::cout << "Consumer: Open/Create shared memory segment" << std::endl;
    boost::interprocess::managed_shared_memory managed_shm{
        boost::interprocess::open_or_create, "SharedMemory_Segment", 1024};
    std::cout << "Consumer: Open/Create mutex" << std::endl;
    boost::interprocess::named_mutex mutex{boost::interprocess::open_or_create,
                                           "SharedMemory_Mutex"};
    std::cout << "Consumer: Open/Create condition" << std::endl;
    boost::interprocess::named_condition condition_read{
        boost::interprocess::open_or_create, "SharedMemory_ConditionRead"};
    boost::interprocess::named_condition condition_write{
        boost::interprocess::open_or_create, "SharedMemory_ConditionWrite"};

    std::cout << "Consumer: Start work" << std::endl;

    do {
      std::cout << "Consumer: Try to get the lock for the shared mutex "
                   "(potential blocking)"
                << std::endl;
      boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock{
          mutex};

      std::cout << "Consumer: Wait for Producer" << std::endl;
      condition_write.wait(lock);

      std::cout << "Consumer: Read data" << std::endl;
      std::pair<int*, int> p = managed_shm.find<int>("SharedMemory_Data");

      if (p.first) {
        std::cout << "Consumer: Found data = " << *p.first << std::endl;

        std::cout << "Consumer: Destroy data" << std::endl;
        managed_shm.destroy<int>("SharedMemory_Data");
      }

      std::cout << "Consumer: Unlock the mutex" << std::endl;
      lock.unlock();

      std::cout << "Consumer: Notify Producer" << std::endl;
      condition_read.notify_one();
    } while (true);
  } catch (const boost::interprocess::interprocess_exception& ex) {
    std::cerr << "boost::interprocess::interprocess_exception: " << ex.what()
              << std::endl;
  } catch (const std::exception& ex) {
    std::cerr << "std::exception: " << ex.what() << std::endl;
  } catch (...) {
    std::cerr << "unhandled exception\n";
  }
}

My questions are:

  1. Are there any problems regarding the four requirements stated above?
  2. What are the problems in my code? What is unnecessary, too complicated or simply plain wrong? (e.g. Are two condition_variables required?, Do both processes need to call notify_one and wait? ...)

Any guidance would be very helpful to me. I'm feeling kind of dumb at the moment.

I am using Boost 1.59.0, Microsoft Visual C++ (MSVC) 19.11.25547 and Windows 10.

Florian Wolters
  • 3,820
  • 5
  • 35
  • 55
  • This question is better suited for http://codereview.stackexchange.com – SergeyA Nov 07 '17 at 22:18
  • Thanks for the hint, I asked the question there: https://codereview.stackexchange.com/questions/179892/producer-consumer-with-boost-interprocess-shared-memory-using-condition-variab. Should I delete/close this question on SO? – Florian Wolters Nov 08 '17 at 08:03

0 Answers0