Just making a simple example because I am having issues with a more complex usecase and want to udnerstand the base case before spending too much time in trial and error.
Scenario: I have two binaries that supposedly takes turns incrementing a number (stored in shared memory). What happens in practice is that the "consumer" app takes over 100% never letting the "creator" run.
If I add a small delay in the consumer in that case I obtain the intended behaviour.
Simple POD struct
#pragma once
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace bip = boost::interprocess;
namespace my_namespace {
static const char *name = "MySharedMemory";
struct MyStruct {
bip::interprocess_mutex mutex;
bip::interprocess_condition cond;
unsigned long counter;
MyStruct(): mutex(), cond(), counter(0) {
}
};
} // namespace my_namespace
"Creator/producer"
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/thread/locks.hpp>
#include "my_struct.h"
bool exit_flag = false;
void my_handler(int) {
exit_flag = true;
}
namespace bip = boost::interprocess;
int main() {
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = my_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
bip::shared_memory_object::remove(my_namespace::name);
auto memory = bip::managed_shared_memory(bip::create_only, my_namespace::name, 65536);
auto *data = memory.construct<my_namespace::MyStruct>(my_namespace::name)();
long unsigned iterations = 0;
while (!exit_flag) {
boost::interprocess::scoped_lock lock(data->mutex);
data->counter++;
std::cout << "iteration:" << iterations << "Counter: " << data->counter << std::endl;
++iterations;
auto start = boost::posix_time::microsec_clock::universal_time();
auto wait_time = start + boost::posix_time::milliseconds(1000);
auto ret = data->cond.timed_wait(lock, wait_time);
if (!ret) {
std::cout << "Timeout" << std::endl;
}
}
return 0;
}
Consumer
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <chrono>
#include <iostream>
#include <thread>
#include <mutex>
#include "my_struct.h"
bool exit_flag = false;
void my_handler(int) {
exit_flag = true;
}
namespace bip = boost::interprocess;
int fib(int x) {
if ((x == 1) || (x == 0)) {
return (x);
} else {
return (fib(x - 1) + fib(x - 2));
}
}
int main() {
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = my_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, nullptr);
auto memory = bip::managed_shared_memory(bip::open_only, my_namespace::name);
auto *data = memory.find<my_namespace::MyStruct>(my_namespace::name).first;
long unsigned iterations = 0;
while (!exit_flag) {
{
boost::interprocess::scoped_lock lock(data->mutex);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
data->counter += 1;
std::cout << "iteration:" << iterations << "Counter: " << data->counter << std::endl;
++iterations;
std::cout << "notify_one" << std::endl;
data->cond.notify_one();
}
// usleep(1); // If I add this it works
}
return 0;
}
If someone can shed some light I would be grateful.