Sharing class pointers between processes - c++

I have a server library which my client executable injects into a remote process.
It is the server's responsibility to set up some sort of IPC/RPC implementation to allow the client to seamlessly communicate with the remote process.
Update
Take a look at the following server-side header:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
using namespace boost::interprocess;
typedef allocator<int, managed_shared_memory::segment_manager> ShmIntAllocator;
typedef vector<int, ShmIntAllocator> IntVector;
class A
{
public:
A();
A(string str, offset_ptr<IntVector> ints)
: m_str(string(str)), m_ints(ints) {};
~A();
string m_str;
offset_ptr<IntVector> m_ints;
};
class B
{
public:
B();
B(offset_ptr<A> obj) : m_obj(obj);
~B();
VOID DoSomethingUseful()
{
MessageBoxA(NULL, m_obj->m_str.c_str(), "SomethingUseful", MB_ICONINFORMATION);
}
offset_ptr<A> m_obj;
};
And here's the server-side implementation:
managed_shared_memory g_shm;
offset_ptr<A> g_objA = nullptr;
PVOID g_hMem = nullptr;
BOOL StartServer()
// Create a shared memory pool
try {
g_shm = managed_shared_memory(create_only, "MySharedMem", OVR_MAPSIZE);
} catch(interprocess_exception& e) {
std::string msg(e.what());
MessageBoxA(NULL, msg.c_str(), "Error", MB_ICONERROR);
return FALSE;
}
// Construct a local class instance
const ShmIntAllocator alloc_intVector (g_shm.get_segment_manager());
offset_ptr<IntVector> ints = g_shm.construct<IntVector>(unique_instance)(alloc_intVector);
ints->push_back(10);
ints->push_back(20);
ints->push_back(30);
g_objA = new A("Testing", ints);
B objB(g_objA);
// Copy data into shared memory
size_t len = sizeof(objB); // <-- Doesn't seem to make a difference if I set this to be something higher
g_hMem = g_shm.allocate(len);
std::memcpy(g_hMem, &objB, len);
return TRUE;
}
VOID StopServer()
{
// Free used resources
if(g_objA) {
delete g_objA;
g_objA = nullptr;
}
try{
g_shm.destroy<B>(unique_instance);
g_shm.deallocate(g_hMem);
g_hMem = nullptr;
shared_memory_object::remove("MySharedMem");
} catch(interprocess_exception& e) {
std::string msg(e.what());
MessageBoxA(NULL, msg.c_str(), "Error", MB_ICONERROR);
}
}
And the client implementation:
BOOL Connect()
{
// Grab the shared memory pool and extract the class
managed_shared_memory shm(open_only, "MySharedMem");
std::pair<B*, std::size_t> ret = shm.find<B>(unique_instance); // <-- Always ends up being 0x00000000!
B *objB = static_cast<B*>(ret.first);
if(!objB) return FALSE;
objB->DoSomethingUseful();
return TRUE;
}
You'll notice that managed_shared_memory::find() always fails to return a valid pointer to the client. But as far as I can tell, the code is perfectly valid. There are no compiler warnings or errors, and everything appears to run smoothly up until this point.
So why is this failing?
How can I get this to work as expected?

Distinct address spaces for pointers
When you are sharing values, everything is clear. For example when put a float value such as 1234.5 in the shared memory, in the other side you can read it simply.
But when you are sharing complex objects (which contain pointers) there is an important problem. The address space of two processes are completely different and distinct. For example you can not put a std::vector object in the shared memory, because it has a pointer to its data in process1 e.g. 0x1ABF212 and this number is meaningless for process2.
So, you have to write down the items of std::vector one by one in the shared memory. Read about Serialization technique to share complex data.
Also, if you're insisting to share complex object as a unique object between processes, you can make those objects with specific memory allocators.
AFAIK Boost.Interprocess has that allocators. It manages shared memory and makes pointers inside the shared memory which is meaningful for both processes.
Sorry for ambiguity, My bad English

You are trying to find B that supposed be created by Unique instance construction. Boost documentation says
The find function obtains a pointer to the only object of type T that can be created using this "unique instance" mechanism.
but in your code you are allocating raw memory and just copy your B object. So your B was not created as Unique instance
So i would suggest change your code as following:
try use
B &objB = *g_shm.construct<B>(unique_instance) (g_objA);
instead of
B objB(g_objA);

Related

C++ smart pointers confusion

I understand that in the C++ realm it is advocated to use smart pointers. I have a simple program as below.
/* main.cpp */
#include <iostream>
#include <memory>
using namespace std;
/* SQLite */
#include "sqlite3.h"
int main(int argc, char** argv)
{
// unique_ptr<sqlite3> db = nullptr; // Got error with this
shared_ptr<sqlite3> db = nullptr;
cout << "Database" << endl;
return 0;
}
When I compile with unique_ptr line got an error message:
error C2027: use of undefined type 'sqlite3'
error C2338: can't delete an incomplete type
When I compile with shared_ptr line it is successful. From several questions and answers my understanding is that unique_ptr should be preferred as I do not intended to have objects sharing resources. What is the best solution in this case? Use shared_ptr or go back to the old approach of bare pointers (new/delete)?
The general approach is in #SomeProgrammerDudes's answer (accept it). But to address your concerns I'm posting this.
You shouldn't go back to raw new and delete. Neither because sqlite3 is an opaque type nor because the overhead of std::shared_ptr. You use, as the other answer specified, a std::unique_tr.
The only difference is how you setup the custom deleter. For std::unique_ptr it's part of the type definition, not a run-time parameter. So you need to do something like this:
struct sqlite3_deleter {
void operator()(sqlite3* sql) {
sqlite3_close_v2(sql);
}
};
using unique_sqlite3 = std::unique_ptr<sqlite3, sqlite3_deleter>;
sqlite3 is an opaque structure (much like FILE from C). All you have is its declaration, not its definition. That means you can't use it in a std::unique_ptr directly without a custom deleter.
#include <memory>
#include <stdexcept>
/* sqlite 3 interface */
struct sqlite3 {};
extern void sqlite3_close(sqlite3*);
extern int sqlite3_open(sqlite3**);
/* our boilerplate */
struct closer
{
void operator()(sqlite3* p) const
{
sqlite3_close(p);
}
};
using sqlite3_ptr = std::unique_ptr<sqlite3, closer>;
/* handy maker function */
sqlite3_ptr make_sqlite()
{
sqlite3* buffer = nullptr;
int err = sqlite3_open(&buffer);
if (err) {
throw std::runtime_error("failed to open sqlite");
}
return sqlite3_ptr(buffer);
}
int main()
{
auto mysqlite = make_sqlite();
}
Solution with shared_ptr
I'm learning C++ and SQLite, so I had this question too. After reading this post, I tried some answers from it. The result is a working example and a small analysis.
First create a custom deleter for the smart pointer.
Then, create an empty share_ptr including the custom deleter
Then, create an empty pointer for the DB handler (sqlite3 * DB;)
Afterwards, open/create the DB.
Link the raw pointer to the shared one.
After the shared_ptr goes out of scope, it will delete the raw pointer too.
This is rather inefficient (see conclusion), but is the only way I manged to use smart pointers with sqlite3, so I decided to post this as an answer.
#include <iostream>
#include<sqlite3.h>
#include<memory>
//Custom deleter
auto del_sqlite3 = [](sqlite3* pSqlite)
{
std::cout << "Calling custom deleter." << std::endl;
sqlite3_close_v2(pSqlite);
};
int main()
{
//Uncomment to run
//const char* dir = "C:\\test\\db_dir\\test.db"
openOrCreateDB(dir);
return 0;
}
int openOrCreateDB(const char* dirName)
{
std::shared_ptr<sqlite3> DB(nullptr, del_sqlite3);//custom deleter
auto pDB = DB.get();
{
int exit = sqlite3_open(dirName, &pDB);
DB.reset(pDB);// Replace nullptr with pDB and link
}
return 0;
}
Why smart pointers with sqlite3?
The main reason to use a smart pointer is to automate memory management and avoid memory leaks. So, this happens if we are thinking in allocating memory on the free store, using new and delete.
But I failed with all my attempts to allocate a database handler in the free store.
Fail 1: using sqlite3* DB = new sqlite3;
int openOrCreateDB(const char* dirName)
{
sqlite3* DB = new sqlite3;//E0070: Incomplete type not allowed
int exit = sqlite3_open(dirName, &DB);
sqlite3_close(DB);
return 0;
}
Fail 2: using share_ptr
static int openOrCreateDB(const char* dirName)
{
std::shared_ptr<sqlite3> DB(new sqlite3, del_sqlite3);// Incomplete type not allowed
auto pDB = DB.get();
{
int exit = sqlite3_open(dirName, &pDB);
DB.reset(pDB);
}
return 0;
}
Fail 3: using make_shared
I didn't even try. In Meyers' Effective Modern C++, Item 21 it is clear that you can't use make_shared to construct a smart pointer on the heap with the custom deleter.
Conclusion
Maybe I'm doing something wrong, but it seems that SQLite does not like to allocate database handlers (sqlite3 objects) on the heap. So why use a smart pointer anyway? Even if you allocate the db handler on the stack, smart pointers uses more memory and more lines of code.
The other reason to use smart pointers is to manage ownership. But, in sqlite3, the workflow is quite repetitive: In a routine:
Create a DB handler.
Open DB, execute SQL statements, etc.
Finalize statement
Finalize DB connection.
So I can't see why should we pass arround a DB handler outside this workflow.
My recommendation is to keep using raw pointers and destroying them with sqlite3_close(sqlite3 * ptr).

Cloning vector of pointers

Hello I'm new here and new to C++. I have a problem where I need to make backup copy of my vector of pointers. But I can't relly get it properly. I found solution to my case on this forum but can't relly get it right:
class cloneFunctor {
public:
T* operator() (T* a) {
return a->clone();
}
}
I tried to implement this into my code but could't get a good resolve, could anyone help me to get this thing right?
My code:
sever.cpp
#include "server.h"
#include <iostream>
#include <functional>
#include <algorithm>
#include <iterator>
class Client;
class cloneFunctor {
public:
cloneFunctor* operator() (cloneFunctor* a) {
return a->clone();
}
};
Server *Server::instance = 0;
Server& Server::getInstance() {
if (instance == 0)
instance = new Server();
return (*instance);
}
void Server::setStatus(bool status) {
this->nStatus = status;
changeClientStatus();
writeStateToConsole();
}
bool Server::getStatus() {
return nStatus;
}
void Server::writeStateToConsole() {
std::cout << "Server state: " << getStatus() << std::endl;
}
void Server::subscribeToServer(Client &temp) {
listOfClients.push_back(&temp);
}
void Server::writeClients() {
for (unsigned int i = 0; i < listOfClients.size(); i++) {
std::cout << i+1 << ". client status: " << listOfClients[i]->getStatus() << std::endl;
}
}
void Server::changeClientStatus() {
if (nStatus == 0){
makeCopy(listOfClients);
for (unsigned int i = 0; i < listOfClients.size(); i++) {
listOfClients[i]->setStatus(false);
}
}
else
restoreCopy();
}
void Server::makeCopy(std::vector<Client *>listOfClients) {
transform(listOfClients.begin(), listOfClients.end(), back_inserter(listOfClientsOld), cloneFunctor());
}
void Server::restoreCopy() {
}
server.h
#ifndef SERVER_H_
#define SERVER_H_
#include "abstractbaseclass.h"
#include "server.h"
#include "client.h"
class Client;
class Server : public Abstractbaseclass {
friend class Client;
public:
static Server& getInstance();
virtual void setStatus(bool status);
virtual bool getStatus();
virtual void writeStateToConsole();
void subscribeToServer(Client &temp);
void writeClients();
void changeClientStatus();
void makeCopy(std::vector<Client *>listOfClients);
void restoreCopy();
private:
static Server *instance;
Server(){};
std::vector <Client *>listOfClients;
std:: vector <Client *> listOfClientsOld;
};
#endif /* SERVER_H_ */
Program should create singleton Server class, and then create 3 clients who will subsribe to server (these are hold in vector of pointers). When I set server status to 0, all clients change their state to off (bool false) and befeore this should be created backup vector, becouse when I'll turn on server again clients need to switch to their state from before shutting down server.
OK, so he's trying to teach some sort of transaction-based thinking.
Client may need an assignment operator
Client & operator=(Client & toCopy)
{
// copy all of toCopy's members over to this
}
if it doesn't already have one and contains pointers or complex data types that you can't trust to self-copy.
Now you can easily
clientA = clientB;
to copy clientB into clientA
Then we get to the main event, Server::restoreCopy(), and it's a brutally simple variant of:
if (listOfClients.size() != listOfClientsOld.size())
{
// back up is stale. Probably throw exception
}
for (size_t index = 0; index < listOfClients.size(); index++)
{
*listOfClients[index] = *listOfClientsOld[index];
}
These are vectors of pointers so you must dereference (*) the pointer to get the pointed at Client or you copy the pointer and not the pointed at. Remember that clone of Client is a totally different Clientand not what Server's user passed in in the first place. If the Server user is still holding onto the initial Client and using it, bad ju-ju will happen if you only copy the pointers. Both sides will be operating on different Clients even though they may look the same. So much as one modification and they won't
You can also use the std::transform trick used to make the back-up here as well, but this is simple and obvious and easy to debug. Feel free to use iterators and range-based for as well.
And while you are at it, pray no one has reordered listOfClients since you made the back-up.
Important side notes:
void makeCopy(std::vector<Client *>listOfClients);
is weird. It allows a Server user to pass in their own vector and add to any existing back-ups. This includes Server itself. It does not remove any existing back up, so listOfClientsOld will keep growing. And because anyone who has access to the Server can call it and pass in their own vector, they can stuff that back up full of fallacious nonsense. I'd recommend that makeCopy take no parameters and remove any existing Clients from the backup, and delete them. Better still, listOfClientsOld has no need to store pointers at all and probably shouldn't.
Lots of pointers in play and no deletes. Somebody has to give back all of that memory you're allocating or you'll eventually run out.

Returning boost::interprocess memory-mapped file from function?

How can I put this code in to a function so that I pass a file path and it returns the file-mapped bytes in to a char array? Whenever I have tried I can never read the contents once the function finishes?
using boost::interprocess;
using boost;
boost::shared_ptr<char> getBytes(const char* FilePath){
shared_ptr<file_mapping> fm(new file_mapping(FilePath, read_only));
shared_ptr<mapped_region> region(new mapped_region(*fm, read_only));
shared_ptr<char> bytes(static_cast<char*>(region->get_address()));
return bytes;
}
You probably need to go about your objective quite differently! Clearly you don't want to just delete the pointer to the memory mapped array which is what the boost::shared_ptr<char> initialized with the pointer to the base address would do. In fact, you probably should not release that pointer at all.
The other two objects you create will go out of scope when getBytes() is exited but these are the objects which actually cling to the shared memory. What you might want to do is to put the file_mapping and the mapped_region together into an object which is put into the returned boost::shared_ptr<char> as a deleter object: this way these two objects would live long enough to keep the pointed to array alive. Upon the deleter function being called the two objects would be released. Here is how this would roughly look like although I haven't checked whether these are indeed the correct interfaces:
struct shared_memory_deleter
{
shared_memory_deleter(char const* file)
: d_fm(new file_mapping(file, read_only))
, d_region(new mapped_region(*fm, read_only))
{
}
void operator()(char*) {
this->d_region.reset(0);
this->d_fm.reset(0);
}
shared_ptr<file_mapping> d_fm;
shared_ptr<mapped_region> d_region);
};
boost::shared_ptr<char> getBytes(const char* FilePath){
shared_memory_deleter deleter(FilePath);
shared_ptr<char> bytes(deleter.d_region->get_address(), deleter);
return bytes;
}
I'm not sure if this would work but it has, at least, a chance. It is probably not a good idea to do something like this. Instead, you are probably much better off wrapping the logic into an object and not using any shared pointers at all:
class shared_memory
{
public:
shared_memory(char const* name)
: d_file(name, read_only)
, d_region(d_file, read_only)
{
}
char const* buffer() const { return d_region.get_address(); }
};

Identify if object is allocated in static memory block (or how to avoid data race conditions)

Preface:
this question is closely related to these ones: ...
- C++: Avoiding Static Initialization Order Problems and Race Conditions Simultaneously
- How to detect where a block of memory was allocated?
... but they have NO positive solution and my actual target use-case is slightly different.
During construction of the object I need to know if it is initialized in static memory bock ( BSS) or is it instantiated in Heap.
The reasons are follow:
Object by itself is designed to be initialized to "all zeros" in constructor - therefore no initialization is needed if object is statically initialized - entire block with all objects is already set to zeros when program is loaded.
Static instances of the object can be used by other statically allocated objects and alter some member variables of the object
Order of initialization of static variables is not pre-determined - i.e. my target object can be invoked before its constructor is invoked, thus altering some of its data, and constructor can be invoked later according to some unknown order of initialization of statics thus clearing already altered data. That is why I'd like to disable code in constructor for statically allocated objects.
Note: in some scenarios Object is the subject for severe multi-threaded access (it has some InterlockedIncrement/Decrement logic), and it has to be completely initialized before any thread can touch it - what i can guaranteed if i explicitly allocate it in Heep, but not in static area (but i need it for static objects too).
Sample piece of code to illustrate the case:
struct MyObject
{
long counter;
MyObject() {
if( !isStaticallyAllocated() ) {
counter = 0;
}
}
void startSomething() { InterlockedIncrement(&counter); }
void endSomething() { InterlockedDecrement(&counter); }
};
At the moment I'm trying to check if 'this' pointer in some predefined range, but this does not work reliably.
LONG_PTR STATIC_START = 0x00400000;
LONG_PTR STATIC_END = 0x02000000;
bool isStatic = (((LONG_PTR)this >= STATIC_START) && (LONG_PTR)this < STATIC_END));
Update:
sample use-case where explicit new operator is not applicable. Code is 'pseudo code', just to illustrate the use-case.
struct SyncObject() {
long counter;
SyncObject() {
if( !isStaticallyAllocated() ) {
counter = 0;
} }
void enter() { while( counter > 0 ) sleep(); counter++; }
void leave() { counter--; }
}
template <class TEnum>
struct ConstWrapper {
SyncObject syncObj;
TEnum m_value;
operator TEnum() const { return m_value; }
LPCTSTR getName() {
syncObj.enter();
if( !initialized ) {
loadNames();
intialized = true;
}
syncObj.leave();
return names[m_value];
}
}
ConstWrapper<MyEnum> MyEnumValue1(MyEnum::Value1);
You can probably achieve this by overwriting the new operator for your class. In your customized new, you can set a "magic byte" within the allocated memory, which you can later check for. This will not permit distinguishing stack from heap, but statically from dynamically allocated objects, which might be sufficient. Note, however, that in the following case
class A {
};
class B {
A a;
};
//...
B* b = new B;
b.a will be considered statically allocated with the proposed method.
Edit: A cleaner, but more complicated solution is probably a further customization of new, where you can keep track of dynamically allocated memory blocks.
Second edit: If you just want to forbid static allocation, why don't you just make the constructor private and add a factory function to the class dynamically creating the object and delivering the pointer?
class A {
private:
A () { ... }
public:
static A* Create () { return new A; }
};
I think that the best way for you to control this is to create a factory for your class. That way you have complete control of how your objects are created instead of making complicated guesses over what memory is used.
The first answer is: not portably, and it may not be possible at all on
some platforms. Under Solaris (and I think Linux as well), there is an
implicitly defined global symbol end, comparison of arbitrary
addresses works, and if this < &end (after the appropriate
conversions), the variable is static, at least as long as no dynamic
loading is involved. But this is far from general. (And it definitely
fails anytime dynamic linking is involved, regardless of the platform.)
The solution I've used in the past was to make the distinction manually.
Basically, I designed the class so that the normal constructor did the
same thing as zero initialization, and I then provided a special no-op
constructor for use with static objects:
class MayBeStatic
{
public:
enum ForStatic { isStatic };
MayBeStatic() { /* equivalent of zero initialization */ };
MayBeStatic( ForStatic ) { /* do absolutely nothing! */ };
// ...
};
When defining an instance with static lifetime, you use the second
constructor:
MayBeStatic object( MayBeStatic::isStatic );
I don't think that this is guaranteed by the standard; I think the
implementation is allowed to modify the memory any way it wants before
invoking the constructor, and in particular, I think it is allowed to
"redo" the zero initialization immediately before invoking the
constructor. None do, however, so you're probably safe in practice.
Alternatively, you can wrap all static instances in a function, so that
they are local statics, and will be initialized the first time the
function is called:
MayBeStatic&
getStaticInstance()
{
static MayBeStatic theInstance;
return theInstance;
}
Of course, you'll need a separate function for each static instance.
It looks like after thinking for a while, I've found a workable solution to identify if block is in static area or not. Let me know, please, if there are potential pitfalls.
Designed for MS Windows, which is my target platform - by another OS I actually meant another version of MS Windows: XP -> Win7. The idea is to get address space of the loaded module (.exe or .dll) and check if block is within this address space. Code which calculates start/end of static area is put into 'lib' segment thus it should be executed before all other static objects from 'user' segment, i.e. constructor can assume that staticStart/End variables are already initialized.
#include <psapi.h>
#pragma warning(push)
#pragma warning(disable: 4073)
#pragma init_seg(compiler)
#pragma warning(pop)
HANDLE gDllHandle = (HANDLE)-1;
LONG_PTR staticStart = 0;
LONG_PTR staticEnd = 0;
struct StaticAreaLocator {
StaticAreaLocator() {
if( gDllHandle == (HANDLE)-1 )
gDllHandle = GetModuleHandle(NULL);
MODULEINFO mi;
GetModuleInformation(GetCurrentProcess(), (HMODULE)gDllHandle, &mi, sizeof(mi));
staticStart = (LONG_PTR)mi.lpBaseOfDll;
staticEnd = (LONG_PTR)mi.lpBaseOfDll + mi.SizeOfImage;
// ASSERT will fail in DLL code if gDllHandle not initialized properly
LONG_PTR current_address;
#if _WIN64
ASSERT(FALSE) // to be adopted later
#else
__asm {
call _here
_here: pop eax ; eax now holds the [EIP]
mov [current_address], eax
}
#endif
ASSERT((staticStart <= current_address) && (current_address < staticEnd));
atexit(cleanup);
}
static void cleanup();
};
StaticAreaLocator* staticAreaLocator = new StaticAreaLocator();
void StaticAreaLocator::cleanup() {
delete staticAreaLocator;
staticAreaLocator = NULL;
}

std::map fails to insert objects

A program I'm making requires access pools of various types of resources, but only accessible to a few classes. The resource pool is also its own class. As such, I decided to use a static class for the resource pool and have others access it this way.
But I am running into a strange problem with adding resources to the pool. Each pool is represented as an std::map, and after insertion, the map still remains empty. I am guessing this has something to do with the map being inside a static class. Is this why maps don't work as intended here?
Relevant code of Resource Pool
class ResourcePool {
private:
static ResourcePool m_ResourcePool;
public:
ResourcePool();
~ResourcePool();
static ResourcePool* Instance() { return &m_ResourcePool; }
// Where textures are stored. ci_less is for case comparison of names
std::map <std::string, TextureResource, ci_less> Textures;
TextureResource* getTexture(std::string handle);
};
Relevant code of how it's used
Scene::Scene() {
Assets = ResourcePool::Instance();
}
TextureResource* Scene::add(std::string handle, TextureResource Texture) {
// Insertion fails
Assets->Textures.insert(std::make_pair(handle + "_tex", Texture));
// I use this line to debug, the map still shows up empty
unsigned size = Assets->Textures.size();
// look up that texture by its name
return Assets->getTexture(handle);
}
The result is, add returns NULL since nothing is found. This program doesn't crash since I'm not doing anything with the texture, just testing out the insertion for now.
Since the question doesn't contain a proper compilable program, I have created one:
#include <string>
#include <map>
#include <iostream>
class ResourcePool {
private:
static ResourcePool m_ResourcePool;
public:
static ResourcePool* Instance() { return &m_ResourcePool; }
std::map <std::string, std::string> Textures;
std::string getTexture(std::string handle) { return Textures[handle]; }
};
ResourcePool ResourcePool::m_ResourcePool;
int main()
{
ResourcePool* Assets = ResourcePool::Instance();
Assets->Textures.insert(std::make_pair("test_tex", "texture"));
std::cout << Assets->Textures.size() << std::endl;
std::cout << Assets->getTexture("test_tex") << std::endl;
return 0;
}
This works on my machine as expected using linux, g++ Debian 4.3.2-1.1.
I wonder if it works for the original poster.