Reputation: 33
I want poll data form external hardware and send the data by a signal.
My code causes a segfault, when wait on a smaphore in shared memory is called and I can not figure out why.
Below a small example of what I'm doing. Basically start two boost threads, one writing data in shared memory, the other reading the data.
The main just starts the ThreadHandler ,sleeps and stops the ThreadHandler.
header:
struct SharedData{
boost::interprocess::interprocess_semaphore sem;
int data;
bool newData;
SharedData():sem(1),newData(false){}
};
class ThreadHandler
{
public:
ThreadHandler();
void start();
void stop();
boost::thread *m_Thread;
boost::thread *m_doerThread;
void doStuff();
void createSharedMemory();
void removeSharedMemory();
SharedData* m_sharedMemory;
};
source:
void getStuff(int id);
void ThreadHandler::start(){
createSharedMemory();
m_doerThread = new boost::thread(boost::bind(&ThreadHandler::doStuff,boost::ref(*this)));
m_Thread = new boost::thread(boost::bind(&getStuff,1));
}
void ThreadHandler::stop(){
m_Thread->interrupt();
m_doerThread->interrupt();
m_Thread->join();
m_doerThread->join();
}
void ThreadHandler::createSharedMemory(){
removeSharedMemory();
try{
boost::interprocess::shared_memory_object sharedObj(boost::interprocess::create_only,SHARED_MEMORY ,boost::interprocess::read_write);
sharedObj.truncate(sizeof(SharedData));
boost::interprocess::mapped_region mappedObj(sharedObj,boost::interprocess::read_write);
SharedData* helper = (SharedData*)mappedObj.get_address();
m_sharedMemory = new (helper) SharedData;
}catch(boost::interprocess::interprocess_exception &ex){
std::cout<<ex.what()<<std::endl;
}catch(std::exception &ex){
std::cout<<ex.what()<<std::endl;
}
}
void ThreadHandler::removeSharedMemory(){
boost::interprocess::shared_memory_object::remove(SHARED_MEMORY);
}
void ThreadHandler::doStuff(){
while(1){
try{
boost::this_thread::yield();
m_sharedMemory->sem.wait();
while(!m_sharedMemory->newData){
m_sharedMemory->sem.post();
boost::this_thread::interruption_point();
boost::this_thread::yield();
m_sharedMemory->sem.wait();
}
//doStuff
m_sharedMemory->newData=false;
m_sharedMemory->sem.post();
}catch(boost::thread_interrupted &interupt){
break;
}catch(std::exception &ex){
std::cout<<ex.what()<<std::endl;
}catch(...){
std::cout<<"exception"<<std::endl;
}
}
}
void getStuff(int id){
SharedData* m_sharedMemory;
try{
boost::interprocess::shared_memory_object sharedObj(boost::interprocess::open_only,SHARED_MEMORY,boost::interprocess::read_write);
boost::interprocess::mapped_region mappedObj(sharedObj,boost::interprocess::read_write);
m_sharedMemory = static_cast<SharedData*>(mappedObj.get_address());
}catch(std::exception &ex){
std::cout<<ex.what()<<std::endl;
}
while(1){
try{
//get Data from hardware
int i =1;
m_sharedMemory->sem.wait();
while(m_sharedMemory->newData){
m_sharedMemory->sem.post();
boost::this_thread::interruption_point();
boost::this_thread::yield();
m_sharedMemory->sem.wait();
}
memcpy(&(m_sharedMemory->data),&i,sizeof(int));
m_sharedMemory->newData=true;
m_sharedMemory->sem.post();
}catch(boost::thread_interrupted& ){
break;
}catch(std::exception &ex){
std::cout<<ex.what()<<std::endl;
}
}
}
I have already tried boost and std mutexes with the same result. Do I handle the shared/mapped memory wrong?
Upvotes: 2
Views: 335
Reputation: 393557
try {
bip::shared_memory_object sharedObj(bip::create_only, SHARED_MEMORY, bip::read_write);
sharedObj.truncate(sizeof(SharedData));
bip::mapped_region mappedObj(sharedObj, bip::read_write);
SharedData *helper = (SharedData *)mappedObj.get_address();
m_sharedMemory = new (helper) SharedData;
} catch (bip::interprocess_exception &ex) {
std::cout << ex.what() << std::endl;
} catch (std::exception &ex) {
std::cout << ex.what() << std::endl;
}
Here, you store a pointer (m_sharedMemory
) to a shared object that goes out of scope as soon as the try
block exits. Boom!
Same problem in the producer:
SharedData *m_sharedMemory;
try {
bip::shared_memory_object sharedObj(bip::open_only, SHARED_MEMORY, bip::read_write);
bip::mapped_region mappedObj(sharedObj, bip::read_write);
m_sharedMemory = static_cast<SharedData *>(mappedObj.get_address());
} catch (std::exception &ex) {
std::cout << ex.what() << std::endl;
}
C++ has deterministic storage lifetimes, and no garbage collection. As the commentor hinted, just sprinkling new
left and right doesn't you any good. In fact, it makes your life a lot worse because now you have to worry about cleanup and exception safety.
Instead, use automatic storage durations (stack, locals, members) but make sure the lifetime of your objects suffices for all code using it.
Here's a fixed demo that seems to do what you want:
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/thread.hpp>
#include <fstream>
#define SHARED_MEMORY "29939FC9-D56B-43A0-AED3-239B8DD4182B"
namespace bip = boost::interprocess;
struct SharedData {
bip::interprocess_semaphore sem;
int data;
bool newData;
SharedData() : sem(1), newData(false) {}
};
struct ThreadHandler {
ThreadHandler() { }
void start();
void stop();
boost::thread m_producer;
boost::thread m_consumer;
void consumer_func();
void createSharedMemory();
void removeSharedMemory();
bip::shared_memory_object m_sharedObj;
bip::mapped_region m_mappedObj;
SharedData *m_sharedMemory = nullptr;
~ThreadHandler() {
stop();
}
};
void producer_func(int);
void ThreadHandler::start() {
createSharedMemory();
m_consumer = boost::thread(&ThreadHandler::consumer_func, this);
m_producer = boost::thread(&producer_func, 1);
}
void ThreadHandler::stop() {
m_producer.interrupt();
m_consumer.interrupt();
m_producer.join();
m_consumer.join();
}
void ThreadHandler::createSharedMemory() {
removeSharedMemory();
try {
m_sharedObj = bip::shared_memory_object(bip::create_only, SHARED_MEMORY, bip::read_write);
m_sharedObj.truncate(sizeof(SharedData));
m_mappedObj = bip::mapped_region(m_sharedObj, bip::read_write);
m_sharedMemory = new (m_mappedObj.get_address()) SharedData;
} catch (bip::interprocess_exception &ex) {
std::cout << ex.what() << std::endl;
} catch (std::exception &ex) {
std::cout << ex.what() << std::endl;
}
}
void ThreadHandler::removeSharedMemory() {
try {
m_sharedMemory = nullptr;
bip::shared_memory_object::remove(SHARED_MEMORY);
} catch(...) {}
}
void ThreadHandler::consumer_func() {
while (1) {
try {
boost::this_thread::yield();
m_sharedMemory->sem.wait();
while (!m_sharedMemory->newData) {
m_sharedMemory->sem.post();
boost::this_thread::interruption_point();
boost::this_thread::yield();
m_sharedMemory->sem.wait();
}
// doStuff
std::cout << "." << std::flush;
m_sharedMemory->newData = false;
m_sharedMemory->sem.post();
} catch (boost::thread_interrupted &interupt) {
break;
} catch (std::exception &ex) {
std::cout << ex.what() << std::endl;
} catch (...) {
std::cout << "exception" << std::endl;
}
}
}
void producer_func(int) {
try {
bip::shared_memory_object sharedObj(bip::open_only, SHARED_MEMORY, bip::read_write);
bip::mapped_region mappedObj(sharedObj, bip::read_write);
auto m_sharedMemory = static_cast<SharedData *>(mappedObj.get_address());
while (1) {
try {
boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
// get Data from hardware
int i = 1;
m_sharedMemory->sem.wait();
while (m_sharedMemory->newData) {
m_sharedMemory->sem.post();
boost::this_thread::interruption_point();
boost::this_thread::yield();
m_sharedMemory->sem.wait();
}
memcpy(&(m_sharedMemory->data), &i, sizeof(int));
m_sharedMemory->newData = true;
m_sharedMemory->sem.post();
} catch (boost::thread_interrupted &) {
break;
} catch (std::exception &ex) {
std::cout << ex.what() << std::endl;
}
}
} catch (std::exception &ex) {
std::cout << ex.what() << std::endl;
}
}
int main() {
ThreadHandler th;
th.start();
boost::this_thread::sleep_for(boost::chrono::seconds(3));
}
Upvotes: 0