I'm trying to share a std::map<std::string, std::chrono::system_clock::time_point> map
: each string is a hostname identifying a site, and the time_point is the last time a process visited that site.
I was trying with mmap
but each process still see its own copy of the map.
Here's my code (I took away all the methods and variables not concerning my problem):
#include <sys/mman.h>
#include <unistd.h>
#include <iostream>
#include <map>
#include <string>
#include <chrono>
typedef std::map<std::string, std::chrono::system_clock::time_point> mymap;
typedef mymap::iterator iter;
typedef mymap* mapPointer;
class MmapManager {
private:
MmapManager() {
frequency = (mapPointer) mmap(NULL, sizeof(frequency), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (frequency == MAP_FAILED) {
std::cout << "mapping failed" << std::endl;
}
};
~MmapManager() {
std::cout << "~MmapManager()" << std::endl;
}
public:
// my class was designed with the singleton pattern
static MmapManager& getInstance() {
static MmapManager instance;
return instance;
}
private:
// pointer to my map
mapPointer frequency;
public:
// check if the process already visited site "host"
bool isHostAlreadyVisited(std::string host) {
return frequency->find(host) != frequency->end();
}
// add new visited site and time of the visit
void addHost(std::string host) {
(*frequency)[host] = std::chrono::system_clock::now();
std::cout << "PROC " << getpid() << " added " << host << std::endl;
}
// get time of the visit for site "host"
std::chrono::system_clock::time_point getElement(std::string host) {
return (*frequency)[host];
}
// print the map
void showMap(void) {
std::cout << "PROC " << getpid() << " prints map keys" << std::endl;
for (auto it = frequency->begin(); it != frequency->end(); ++it) {
std::cout << it->first << std::endl;
}
}
};
int main(void) {
// simulate the processes
for (int i=0; i<5; i++) {
// child process
if (fork() == 0) {
// if child never visited this site...
if (! MmapManager::getInstance().isHostAlreadyVisited("www.google.com")) {
std::cout << "PID " << getpid() << " www.google.com is new" << std::endl;
// ...add it to the map
MmapManager::getInstance().addHost("www.google.com");
}
else {
// if child already visited it, calculate
// how much time passed since last visit
auto now = std::chrono::system_clock::now();
auto before = MmapManager::getInstance().getElement("www.google.com");
std::chrono::duration<double> diff = now-before;
std::cout << "PID " << getpid() << " visited www.google.com " << diff.count() << " seconds ago" << std::endl;
}
MmapManager::getInstance().showMap();
_exit(EXIT_SUCCESS);
}
}
return 0;
}
Here's one of the possible outputs:
PID 12457 www.google.com is new
PID 12459 www.google.com is new
PID 12458 www.google.com is new
PID 12460 www.google.com is new
PID 12461 www.google.com is new
I can't use other external libraries like Boost or use threads: I know they share memory, but the program was designed this way (with child processes doing stuff) and I can't modify it (original code is not mine).
Why does each process still see its own copy of the map?
Aucun commentaire:
Enregistrer un commentaire