Created
November 1, 2020 18:58
-
-
Save caiorss/d5f8db63803859f6182e271e026498e3 to your computer and use it in GitHub Desktop.
Experiment code for POSIX Shared memory IPC on Unix systems
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <cassert> | |
#include <cstring> | |
// ----- Unix and Posix headers ---// | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
// Implementation of object allocated in Shared memory | |
struct Object | |
{ | |
int x = 0; | |
double y = 26.2124214; | |
char dataset[400] = "Hello world"; | |
Object(){ | |
std::cout << " [TRACE] Object created Ok \n" << '\n'; | |
} | |
void set_x(int x) { this->x = x; } | |
void set_y(double y) { this->y = y; } | |
void set_str(const char* value) | |
{ | |
mempcpy(dataset, value, 200); | |
} | |
void show() const | |
{ | |
std::cout << " [TRACE] Shared memory object =>> " | |
<< " ; x = " << x | |
<< " ; y = " << y | |
<< " ; str = " << dataset | |
<< '\n'; | |
} | |
}; | |
constexpr int FAILURE = -1; | |
constexpr size_t STORAGE_SIZE = sizeof(Object); | |
constexpr const char* shared_memory_name = "/shared-data"; | |
// Provides shared memory object. | |
void server_side(const char* shm_name); | |
// Consumes shared memory object. | |
void client_side(const char* shm_name); | |
int main(int argc, char** argv) | |
{ | |
std::cout << " [INFO] Process Unique Identifier PID = " << ::getpid() << '\n'; | |
std::cout << " [INFO] Storage size in bytes = " << STORAGE_SIZE << '\n'; | |
if(argc < 2){ | |
std::cerr << " [ERROR] Expected command argument. " << '\n'; | |
return EXIT_FAILURE; | |
} | |
auto command = std::string{argv[1]}; | |
if(command == "server" ){ server_side(shared_memory_name); } | |
if(command == "client" ){ client_side(shared_memory_name); } | |
return 0; | |
} | |
// ========= I M P L E M E N T A T I O N S =================// | |
void server_side(const char* shm_name) | |
{ | |
// Remove shared memory segment if it already exists. | |
::shm_unlink(shm_name); | |
// Attempt to create shared memory segment | |
// On Linux this segment corresponds to the file: '/dev/shm/<SHM-NAME>' | |
int fd = shm_open( shm_name | |
, O_CREAT | O_EXCL | O_RDWR | |
, S_IRUSR | S_IWUSR | |
); | |
// assert => Placeholder for future error handling | |
assert( fd != FAILURE && "Failed to create shared memory segment" ); | |
// Resize shared memory segment | |
assert( ::ftruncate(fd, STORAGE_SIZE) != FAILURE ); | |
// Map shared memory segment into process address space | |
void* pmap = ::mmap( nullptr // Most of the time set to nullptr | |
, STORAGE_SIZE // Size of memory mapping | |
, PROT_READ | PROT_WRITE // Allows reading and writing operations | |
, MAP_SHARED // This flag makes this segment visible by other processes. | |
, fd // File descriptor | |
, 0x00 // Offset from beggining of file | |
); | |
if(pmap == MAP_FAILED){ perror("mmap"); exit(EXIT_FAILURE); } | |
// Allocate object in shared memory segment | |
// using placement 'new operator' | |
Object* pObj = new (pmap) Object; | |
assert( pObj != nullptr ); | |
std::cout << " [BEFORE] Before typing RETURN " << '\n'; | |
pObj->show(); | |
std::cout << "\n\n Type return to exit" << '\n'; | |
std::getchar(); | |
std::cout << " [BEFORE] After typing RETURN " << '\n'; | |
pObj->show(); | |
// Mmap cleanup procedure | |
assert( ::munmap(pmap, STORAGE_SIZE) != FAILURE ); | |
// Remove shared memory segment | |
::shm_unlink(shm_name); | |
} | |
void client_side(const char* shm_name) | |
{ | |
// Attempt to create shared memory segment | |
int fd = ::shm_open( shm_name, O_RDWR, 0); | |
// assert => Placeholder for future error handling | |
assert( fd != - 1 && "Failed to open shared memory segment" ); | |
// Map shared memory segment into process address space | |
void* pmap = ::mmap( nullptr // Most of the time to NULL or nullptr | |
, sizeof STORAGE_SIZE // Size of memory mapping | |
, PROT_READ | PROT_WRITE // Allows reading and writing operations | |
, MAP_SHARED // This flag makes this segment visible by other processes. | |
, fd // File descriptor | |
, 0x00 // Offset from beggining of file | |
); | |
if(pmap == MAP_FAILED){ perror("mmap"); exit(EXIT_FAILURE); } | |
/* Load object from shared memory knowing only its interface | |
* (pointer to interface class), without knowing its exact | |
* implementation or type. | |
*/ | |
Object* pObj = reinterpret_cast<Object*>(pmap); | |
std::cout << " Previous object value " << '\n'; | |
pObj->show(); | |
int x; | |
double y; | |
std::string str; | |
std::cout << "Enter x, y and str: "; | |
std::cin >> x >> y >> str; | |
pObj->set_x(x); | |
pObj->set_y(y); | |
pObj->set_str(str.c_str()); | |
pObj->show(); | |
// assert( ::munmap(pmap, STORAGE_SIZE) != FAILURE ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment