SlideShare a Scribd company logo
/**
* @mainpage
* @anchor mainpage
* @brief
* @details
* @copyright Russell John Childs, PhD, 2017
* @author Russell John Childs, PhD
* @date 2017-02-26
*
* This file contains classes: SharedMemoryHashTable
*
* SharedMemoryHashTable implements a hash table using shared memory instead of
* heap memory. Two blocks of shared memory are created. The first is for the
* buckets. The second is "heap memory" for the linked list nodes that hold hash
* collisions. Each node contains a "next pointer" that holds the array index
* into the second block where the next node in the linked list resides. A C++
* placement new is used to initialise each node in shared memory. A simple
* memory management model is used for new/delete on Shared Memory involving a
* linked list of free memory slots that may be pushed and popped.
*
* Currently, only a subset of the interface for std::unordered_set/map is
* offered (insertions+deletions). In a future release, STL Allocators will be
* implemented that allow Shared Memory to be used for STL container classes.
*
* Compiled and tested under Linux Mint, using g++ 4.8.
*
* g++ options: -O0 -g3 -Wall -O0 -fopenmp -mavx -m64 -g -Wall -c
* -fmessage-length=0 -fno-omit-frame-pointer --fast-math
* -std=c++11 -I/opt/intel/vtune_amplifier_xe_2013/include/
*
* Linker options: -Wl,--no-as-needed -fopenmp
* -L/opt/intel/vtune_amplifier_xe_2013/lib64/
*
* Cmd line options: -lpthread -latomic -littnotify -ldl -lrt
*
* Documentation: Doxygen comments for interfaces, normal for impl.
*
* @file shared_memory_hash_table.cpp
* @see
* @ref mainpage
*/
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <iostream>
#include <string>
#include <functional>
/**
* addtogroup SharedMemoryContainers
* @{
*/
namespace SharedMemoryContainers
{
/**
* This class implements a hash table using shared memory instead of
* heap memory. Two blocks of shared memory are created. The first is for the
* buckets. The second is "heap memory" for the linked list nodes that hold hash
* collisions. Each node contains a "next pointer" that holds the array index
* into the second block where the next node in the linked list resides. A C++
* placement new is used to initialise each node in shared memory. A simple
* memory management model is used for new/delete on Shared Memory involving a
* linked list of free memory slots that may be pushed and popped.
*
* Currently, only a subset of the interface for std::unordered_set/map is
* offered (insertions+deletions). In a future release, STL Allocators will be
* implemented that allow Shared Memory to be used for STL container classes.
*
* Notes: The user type T must provide:
*
* (1) A default ctor
*
* (2) operator std::string(void) that returns a unique ID as an std::string of
* the form "/key" where key is some set of chars excluding '/'.
*
* @tparam T - The type of the item to be stored in hash map.
* @tparam Size - The number of buckets.
* @tparam NumItems - Number of items to be stored.
*
*/
template<typename T,unsigned Size,unsigned NumItems> class SharedMemoryHashTable
{
public:
/**
* Creates or accesses hash table in shared memory
*
* @param init {bool = false} - true iff hash table is being created, false
* if it already exists and is being accessed by a process.
*
* @param key {const std::string&="/shared_memory_hash_table"} - unique key
* for the shared memory of the form "/key" where key is some set of chars
* excluding '/'.
*
*/
SharedMemoryHashTable(
bool init = false, const std::string& key="/shared_memory_hash_table") :
m_key(key.c_str()),
m_buckets(0),
m_shared(0),
m_free(0)
{
//Shared memory for buckets
auto size = sizeof(unsigned)*Size;
auto shmid = shm_open(key.c_str(), O_CREAT | O_RDWR, 0666);
if(errno!=0) perror("shm_open: ");
ftruncate(shmid,size);
auto prot = PROT_READ | PROT_WRITE;
m_buckets=
static_cast<unsigned*>(mmap(0,size,prot,MAP_SHARED,shmid,0));
if(init) for(unsigned i=0; i<Size; ++i) m_buckets[i]=0;
close(shmid);
//Shared memory for linked list nodes
size = sizeof(LinkedList)*(NumItems+1);
shmid = shm_open((key+"nodes").c_str(), O_CREAT | O_RDWR, 0666);
if(errno!=0) perror("shm_open: ");
ftruncate(shmid,size);
m_shared=static_cast<LinkedList*>(mmap(0,size,prot,MAP_SHARED,shmid,0));
//Stored "ptr" to free memory in m_shared[0] so all processes see it
m_free = &m_shared->m_next;
close(shmid);
//Create "heap" of free memory (linked list of free slots)
if(init)
{
for(unsigned i=1; i <= NumItems; ++i)
{
(m_shared+*m_free)->m_next = i;
*m_free = i;
}
m_free = &(m_shared->m_next=1);
}
}
/**
* Detach shared memory associated with this hash table
*/
~SharedMemoryHashTable(void)
{
munmap(m_shared, NumItems*sizeof(LinkedList));
munmap(m_buckets, sizeof(unsigned)*Size);
shm_unlink(m_key.c_str());
shm_unlink((m_key+"nodes").c_str());
}
/**
* This class provides the linked list for hash collisions.
*
*/
struct LinkedList
{
T m_data;
unsigned m_next;
/**
* @param data {const T&} - item to be placed in linked list node
*/
LinkedList(const T& data = T()) :
m_data(data),
m_next(0)
{
}
/**
* Dtor
*/
~LinkedList(void)
{
}
};
/**
* @param key {const std::string&} - unique item id to be searched for
*
* @return T* - reference to item with specified id or NULL if not found
*
*/
T* find(const std::string& key)
{
T* ret_val = 0;
//Convert key to bucket array index
auto index = std::hash<std::string>{}(key)%Size;
//Search for key
auto next = m_buckets[index];
while( next != 0 && ret_val==0)
{
//If key found ...
if(std::string((m_shared+next)->m_data)==key)
{
//Return value = found item
ret_val = &(m_shared+next)->m_data;
}
//Keep traversing linked list
next=(m_shared+next)->m_next;
}
return ret_val;
}
/**
* @param key {const std::string&} - unique item id
*
* @param in {const T&} - item to be inserted
*
* @return std::pair<T*, bool> - {existing_item_address, false} iff item
* already exists, {inserted_item_address, true} if item does not exist
*
*/
std::pair<T*, bool> insert(const std::string& key, const T& in)
{
//Get item if it exists, or NULL
T* ret_val = find(key);
bool is_success = false;
//If item does not exist, create it on the Shared Memory "heap"
if(ret_val==0)
{
//Convert key to bucket array index
auto index = std::hash<std::string>{}(key)%Size;
//Create new linked list node and return reference to stored item
unsigned free_slot = *m_free;
*m_free = (m_shared+*m_free)->m_next;
LinkedList* linked_list =new(m_shared+free_slot) LinkedList(in);
linked_list->m_next=m_buckets[index];
m_buckets[index]=free_slot;
//new item and success
ret_val = &linked_list->m_data;
is_success = true;
}
return std::make_pair(ret_val, is_success);
}
/**
* @param key {const std::string&} - unique item id
*
* @return T& - reference to item with specified id
*
*/
T& operator[](const std::string& key)
{
return *insert(key, T()).first;
}
/**
* @param key {const std::string&} - unique item id
*
* @param in {const T&} - item to be inserted
*
* @return std::pair<T*, bool> - {existing_item_address, false} iff item
* already exists, {inserted_item_address, true} if item does not exist
*
*/
void erase(const std::string& key)
{
//Convert key to bucket array index
auto index = std::hash<std::string>{}(key)%Size;
//Search for key
auto prev = m_buckets[index];
auto next = prev;
while( next != 0 )
{
//If key found ...
if(std::string((m_shared+next)->m_data)==key)
{
//delete found item
if(prev==m_buckets[index]) m_buckets[index] =
((m_shared+prev)->m_next=(m_shared+next)->m_next);
(m_shared+next)->m_next = *m_free;
*m_free = next;
}
//Keep traversing linked list
prev = next;
next=(m_shared+next)->m_next;
}
}
private:
std::string m_key;
unsigned* m_buckets;
LinkedList* m_shared;
unsigned* m_free;
};
}
/**
* @}
*/
int main(void)
{
using namespace SharedMemoryContainers;
//Raw Data
struct RawData
{
unsigned m_user_id;
unsigned m_dest_id;
std::string m_branch;
operator std::string(void)
{
return std::string(m_branch);
}
};
//Create a 100-bucket hash table
const int buckets = 100;
const int items = 5;
typedef SharedMemoryHashTable<RawData, buckets, items> Table;
Table shared_memory_hash_table(true);
//Parent process
unsigned user_id = 0;
unsigned dest_id = 1000;
//Insert values into shared memory hash table
std::cout << "=====================================" << std::endl;
std::cout << "Inserting values via parent process" << std::endl;
//Loop over keys
for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"})
{
//Insert item into hash table
RawData raw_data = RawData{user_id++, dest_id--, str};
//str.copy(raw_data.m_branch, str.size());
if(str == "a")
{
shared_memory_hash_table.insert(raw_data.m_branch, raw_data);
}
else
{
shared_memory_hash_table[raw_data.m_branch]=raw_data;
}
std::cout << "hash_table[" << raw_data.m_branch << "]={"
<< raw_data.m_user_id << ", "
<< raw_data.m_dest_id << ", "
<< raw_data.m_branch << "}"
<< std::endl;
//Validate insertion
std::cout << "Verify: hash_table[" << raw_data.m_branch << "] == {"
<< shared_memory_hash_table[raw_data.m_branch].m_user_id << ", "
<< shared_memory_hash_table[raw_data.m_branch].m_dest_id << ", "
<< shared_memory_hash_table[raw_data.m_branch].m_branch << "}"
<< std::endl;
}
//Fork child process
pid_t p_id = fork();
if (p_id == 0)
{
Table shared_memory_hash_table;
//Extract values from shared memory hash table
std::cout << "=====================================" << std::endl;
std::cout << "Extracting values via child process" << std::endl;
//Loop over keys
for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"})
{
//Find item for given key
auto& item = shared_memory_hash_table[str.c_str()];
std::cout << "hash_table[" << str << "] == {"
<< item.m_user_id << ", "
<< item.m_dest_id << ", "
<< item.m_branch << "}"
<< std::endl;
}
std::cout << "=====================================" << std::endl;
std::cout << "deleting key="bb" via child process" << std::endl;
shared_memory_hash_table.erase("bb");
std::cout << "Extracting values left via child process" << std::endl;
for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"})
{
//Find item for given key
auto item = shared_memory_hash_table.find(str.c_str());
if(item !=0)
{
std::cout << "hash_table[" << str << "] == {"
<< item->m_user_id << ", "
<< item->m_dest_id << ", "
<< item->m_branch << "}"
<< std::endl;
}
else
{
std::cout << str << " not found in hash table." << std::endl;
}
}
std::cout << "=====================================" << std::endl;
}
else
{
int status;
waitpid(p_id, &status, 0);
std::cout << "=====================================" << std::endl;
std::cout << "Extracting values left via parent process" << std::endl;
for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"})
{
//Find item for given key
auto item = shared_memory_hash_table.find(str.c_str());
if(item !=0)
{
std::cout << "hash_table[" << str << "] == {"
<< item->m_user_id << ", "
<< item->m_dest_id << ", "
<< item->m_branch << "}"
<< std::endl;
}
else
{
std::cout << str << " not found in hash table." << std::endl;
}
}
}
return 0;
}

More Related Content

PDF
Where's My SQL? Designing Databases with ActiveRecord Migrations
PPTX
Ciklum net sat12112011-alexander fomin-expressions and all, all, all
PDF
Ecto DSL Introduction - Yurii Bodarev
PDF
Recursion to iteration automation.
PDF
Algorithms devised for a google interview
PDF
Interview C++11 code
PDF
IBM Kinexa Prove It! C programming test results.
PDF
InterTech provide international construction services - www.ooo-intertech.com...
Where's My SQL? Designing Databases with ActiveRecord Migrations
Ciklum net sat12112011-alexander fomin-expressions and all, all, all
Ecto DSL Introduction - Yurii Bodarev
Recursion to iteration automation.
Algorithms devised for a google interview
Interview C++11 code
IBM Kinexa Prove It! C programming test results.
InterTech provide international construction services - www.ooo-intertech.com...

Viewers also liked (18)

DOC
Brain mri reports
PDF
Randy Kerns, CIC, ChFC – Proactive Advisor Magazine – Volume 5 Issue 1
PDF
Jerry Ganz, CFP – Proactive Advisor Magazine – Volume 5 Issue 3
PDF
Jeff Pesta, LUTCF – Proactive Advisor Magazine – Volume 5 Issue 11
PDF
9 orange square 8 love
PPTX
B2 5 Monitors
PPTX
Entradablog
PDF
Johnathon Davis – Proactive Advisor Magazine – Volume 6, Issue 2
PDF
Chris Gurnee – Proactive Advisor Magazine – Volume 6, Issue 3
PDF
Bob Pearson – Proactive Advisor Magazine – Volume 6, Issue 11
PDF
Ryan Finnell – Proactive Advisor Magazine – Volume 6, Issue 9
PDF
Don Meredith, CRPC – Proactive Advisor Magazine – Volume 6, Issue 5
PDF
Phylyp Wagner, CFP & Matt Quattlebaum, CFP – Proactive Advisor Magazine – Vol...
PDF
Trish Beine – Proactive Advisor Magazine – Volume 5 Issue 2
PPTX
Toronto’s attractions!
PPTX
Tugas PPKN
PDF
Brian Glaze & Larry Ware, CRPC, CLTC – Proactive Advisor Magazine – Volume 5 ...
PDF
Dirac demo (quantum mechanics with C++). Please note: There is a problem with...
Brain mri reports
Randy Kerns, CIC, ChFC – Proactive Advisor Magazine – Volume 5 Issue 1
Jerry Ganz, CFP – Proactive Advisor Magazine – Volume 5 Issue 3
Jeff Pesta, LUTCF – Proactive Advisor Magazine – Volume 5 Issue 11
9 orange square 8 love
B2 5 Monitors
Entradablog
Johnathon Davis – Proactive Advisor Magazine – Volume 6, Issue 2
Chris Gurnee – Proactive Advisor Magazine – Volume 6, Issue 3
Bob Pearson – Proactive Advisor Magazine – Volume 6, Issue 11
Ryan Finnell – Proactive Advisor Magazine – Volume 6, Issue 9
Don Meredith, CRPC – Proactive Advisor Magazine – Volume 6, Issue 5
Phylyp Wagner, CFP & Matt Quattlebaum, CFP – Proactive Advisor Magazine – Vol...
Trish Beine – Proactive Advisor Magazine – Volume 5 Issue 2
Toronto’s attractions!
Tugas PPKN
Brian Glaze & Larry Ware, CRPC, CLTC – Proactive Advisor Magazine – Volume 5 ...
Dirac demo (quantum mechanics with C++). Please note: There is a problem with...
Ad

Similar to Shared_memory_hash_table (20)

PDF
This project will implement a simple usernamepassword lookup system.pdf
DOCX
(C++ exercise) 3. Implement a circular, doubly linked list with a ha.docx
PDF
Describe a data structure to represent sets of elements (each element.pdf
PDF
Do the following program in C++- Create a item class... with and i.pdf
PDF
program on string in java Lab file 2 (3-year)
PDF
C++ projectMachine Problem 7 - HashingWrite a program to do the .pdf
PDF
#ifndef LINKED_LIST_ #define LINKED_LIST_ templateclass It.pdf
DOCX
(C++ exercise) 1.Implement a circular, doubly linked list with a has.docx
DOCX
lab08build.bat@echo offclsset DRIVE_LETTER=1s.docx
PDF
include ltfunctionalgt include ltiteratorgt inclu.pdf
PDF
DS & Algo 1 - C++ and STL Introduction
PDF
2309.09359.pdf
PDF
2309.09359.pdf
DOCX
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
PDF
Using c++Im also using a the ide editor called CodeLiteThe hea.pdf
PPTX
C++11 - STL Additions
PDF
This assignment and the next (#5) involve design and development of a.pdf
PDF
Implement a priority queue using a doublyLinked-cpp where the node wit.pdf
PDF
Sppu University|BE|Computer Engineering|OOPs|unit 6 notes|ppt
DOCX
#include stdafx.h #include iostream using namespace std;vo.docx
This project will implement a simple usernamepassword lookup system.pdf
(C++ exercise) 3. Implement a circular, doubly linked list with a ha.docx
Describe a data structure to represent sets of elements (each element.pdf
Do the following program in C++- Create a item class... with and i.pdf
program on string in java Lab file 2 (3-year)
C++ projectMachine Problem 7 - HashingWrite a program to do the .pdf
#ifndef LINKED_LIST_ #define LINKED_LIST_ templateclass It.pdf
(C++ exercise) 1.Implement a circular, doubly linked list with a has.docx
lab08build.bat@echo offclsset DRIVE_LETTER=1s.docx
include ltfunctionalgt include ltiteratorgt inclu.pdf
DS & Algo 1 - C++ and STL Introduction
2309.09359.pdf
2309.09359.pdf
lab03build.bat@echo offclsset DRIVE_LETTER=1set.docx
Using c++Im also using a the ide editor called CodeLiteThe hea.pdf
C++11 - STL Additions
This assignment and the next (#5) involve design and development of a.pdf
Implement a priority queue using a doublyLinked-cpp where the node wit.pdf
Sppu University|BE|Computer Engineering|OOPs|unit 6 notes|ppt
#include stdafx.h #include iostream using namespace std;vo.docx
Ad

More from Russell Childs (20)

PDF
spinor_quantum_simulator_user_guide_.pdf
PDF
String searching o_n
PDF
String searching o_n
PDF
String searching o_n
PDF
String searching
PDF
PDF
PDF
Feature extraction using adiabatic theorem
PDF
Feature extraction using adiabatic theorem
PDF
Wavelets_and_multiresolution_in_two_pages
PDF
Relativity 2
PDF
Full resume dr_russell_john_childs_2016
PDF
Simple shared mutex UML
PDF
Design pattern to avoid downcasting
PDF
Interview uml design
PDF
Full_resume_Dr_Russell_John_Childs
PDF
Dynamic programming burglar_problem
PDF
K d tree_cpp
PDF
Multithreaded sockets c++11
PDF
IBM Kinexa Prove It! C++ programming test results.
spinor_quantum_simulator_user_guide_.pdf
String searching o_n
String searching o_n
String searching o_n
String searching
Feature extraction using adiabatic theorem
Feature extraction using adiabatic theorem
Wavelets_and_multiresolution_in_two_pages
Relativity 2
Full resume dr_russell_john_childs_2016
Simple shared mutex UML
Design pattern to avoid downcasting
Interview uml design
Full_resume_Dr_Russell_John_Childs
Dynamic programming burglar_problem
K d tree_cpp
Multithreaded sockets c++11
IBM Kinexa Prove It! C++ programming test results.

Recently uploaded (20)

PDF
AI in Product Development-omnex systems
PDF
System and Network Administraation Chapter 3
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PPTX
ai tools demonstartion for schools and inter college
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PPTX
L1 - Introduction to python Backend.pptx
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
How Creative Agencies Leverage Project Management Software.pdf
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PPTX
Transform Your Business with a Software ERP System
PPTX
Introduction to Artificial Intelligence
PDF
Design an Analysis of Algorithms II-SECS-1021-03
AI in Product Development-omnex systems
System and Network Administraation Chapter 3
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
ai tools demonstartion for schools and inter college
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Odoo Companies in India – Driving Business Transformation.pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Which alternative to Crystal Reports is best for small or large businesses.pdf
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Navsoft: AI-Powered Business Solutions & Custom Software Development
2025 Textile ERP Trends: SAP, Odoo & Oracle
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
L1 - Introduction to python Backend.pptx
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
How Creative Agencies Leverage Project Management Software.pdf
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Transform Your Business with a Software ERP System
Introduction to Artificial Intelligence
Design an Analysis of Algorithms II-SECS-1021-03

Shared_memory_hash_table

  • 1. /** * @mainpage * @anchor mainpage * @brief * @details * @copyright Russell John Childs, PhD, 2017 * @author Russell John Childs, PhD * @date 2017-02-26 * * This file contains classes: SharedMemoryHashTable * * SharedMemoryHashTable implements a hash table using shared memory instead of * heap memory. Two blocks of shared memory are created. The first is for the * buckets. The second is "heap memory" for the linked list nodes that hold hash * collisions. Each node contains a "next pointer" that holds the array index * into the second block where the next node in the linked list resides. A C++ * placement new is used to initialise each node in shared memory. A simple * memory management model is used for new/delete on Shared Memory involving a * linked list of free memory slots that may be pushed and popped. * * Currently, only a subset of the interface for std::unordered_set/map is * offered (insertions+deletions). In a future release, STL Allocators will be * implemented that allow Shared Memory to be used for STL container classes. * * Compiled and tested under Linux Mint, using g++ 4.8. * * g++ options: -O0 -g3 -Wall -O0 -fopenmp -mavx -m64 -g -Wall -c * -fmessage-length=0 -fno-omit-frame-pointer --fast-math * -std=c++11 -I/opt/intel/vtune_amplifier_xe_2013/include/ * * Linker options: -Wl,--no-as-needed -fopenmp * -L/opt/intel/vtune_amplifier_xe_2013/lib64/ * * Cmd line options: -lpthread -latomic -littnotify -ldl -lrt * * Documentation: Doxygen comments for interfaces, normal for impl. * * @file shared_memory_hash_table.cpp * @see * @ref mainpage */ #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <sys/wait.h> #include <errno.h> #include <iostream> #include <string> #include <functional> /** * addtogroup SharedMemoryContainers * @{ */ namespace SharedMemoryContainers { /** * This class implements a hash table using shared memory instead of * heap memory. Two blocks of shared memory are created. The first is for the * buckets. The second is "heap memory" for the linked list nodes that hold hash * collisions. Each node contains a "next pointer" that holds the array index * into the second block where the next node in the linked list resides. A C++ * placement new is used to initialise each node in shared memory. A simple
  • 2. * memory management model is used for new/delete on Shared Memory involving a * linked list of free memory slots that may be pushed and popped. * * Currently, only a subset of the interface for std::unordered_set/map is * offered (insertions+deletions). In a future release, STL Allocators will be * implemented that allow Shared Memory to be used for STL container classes. * * Notes: The user type T must provide: * * (1) A default ctor * * (2) operator std::string(void) that returns a unique ID as an std::string of * the form "/key" where key is some set of chars excluding '/'. * * @tparam T - The type of the item to be stored in hash map. * @tparam Size - The number of buckets. * @tparam NumItems - Number of items to be stored. * */ template<typename T,unsigned Size,unsigned NumItems> class SharedMemoryHashTable { public: /** * Creates or accesses hash table in shared memory * * @param init {bool = false} - true iff hash table is being created, false * if it already exists and is being accessed by a process. * * @param key {const std::string&="/shared_memory_hash_table"} - unique key * for the shared memory of the form "/key" where key is some set of chars * excluding '/'. * */ SharedMemoryHashTable( bool init = false, const std::string& key="/shared_memory_hash_table") : m_key(key.c_str()), m_buckets(0), m_shared(0), m_free(0) { //Shared memory for buckets auto size = sizeof(unsigned)*Size; auto shmid = shm_open(key.c_str(), O_CREAT | O_RDWR, 0666); if(errno!=0) perror("shm_open: "); ftruncate(shmid,size); auto prot = PROT_READ | PROT_WRITE; m_buckets= static_cast<unsigned*>(mmap(0,size,prot,MAP_SHARED,shmid,0)); if(init) for(unsigned i=0; i<Size; ++i) m_buckets[i]=0; close(shmid); //Shared memory for linked list nodes size = sizeof(LinkedList)*(NumItems+1); shmid = shm_open((key+"nodes").c_str(), O_CREAT | O_RDWR, 0666); if(errno!=0) perror("shm_open: "); ftruncate(shmid,size); m_shared=static_cast<LinkedList*>(mmap(0,size,prot,MAP_SHARED,shmid,0)); //Stored "ptr" to free memory in m_shared[0] so all processes see it m_free = &m_shared->m_next; close(shmid); //Create "heap" of free memory (linked list of free slots) if(init) { for(unsigned i=1; i <= NumItems; ++i) {
  • 3. (m_shared+*m_free)->m_next = i; *m_free = i; } m_free = &(m_shared->m_next=1); } } /** * Detach shared memory associated with this hash table */ ~SharedMemoryHashTable(void) { munmap(m_shared, NumItems*sizeof(LinkedList)); munmap(m_buckets, sizeof(unsigned)*Size); shm_unlink(m_key.c_str()); shm_unlink((m_key+"nodes").c_str()); } /** * This class provides the linked list for hash collisions. * */ struct LinkedList { T m_data; unsigned m_next; /** * @param data {const T&} - item to be placed in linked list node */ LinkedList(const T& data = T()) : m_data(data), m_next(0) { } /** * Dtor */ ~LinkedList(void) { } }; /** * @param key {const std::string&} - unique item id to be searched for * * @return T* - reference to item with specified id or NULL if not found * */ T* find(const std::string& key) { T* ret_val = 0; //Convert key to bucket array index auto index = std::hash<std::string>{}(key)%Size; //Search for key auto next = m_buckets[index]; while( next != 0 && ret_val==0) { //If key found ... if(std::string((m_shared+next)->m_data)==key) { //Return value = found item
  • 4. ret_val = &(m_shared+next)->m_data; } //Keep traversing linked list next=(m_shared+next)->m_next; } return ret_val; } /** * @param key {const std::string&} - unique item id * * @param in {const T&} - item to be inserted * * @return std::pair<T*, bool> - {existing_item_address, false} iff item * already exists, {inserted_item_address, true} if item does not exist * */ std::pair<T*, bool> insert(const std::string& key, const T& in) { //Get item if it exists, or NULL T* ret_val = find(key); bool is_success = false; //If item does not exist, create it on the Shared Memory "heap" if(ret_val==0) { //Convert key to bucket array index auto index = std::hash<std::string>{}(key)%Size; //Create new linked list node and return reference to stored item unsigned free_slot = *m_free; *m_free = (m_shared+*m_free)->m_next; LinkedList* linked_list =new(m_shared+free_slot) LinkedList(in); linked_list->m_next=m_buckets[index]; m_buckets[index]=free_slot; //new item and success ret_val = &linked_list->m_data; is_success = true; } return std::make_pair(ret_val, is_success); } /** * @param key {const std::string&} - unique item id * * @return T& - reference to item with specified id * */ T& operator[](const std::string& key) { return *insert(key, T()).first; } /** * @param key {const std::string&} - unique item id * * @param in {const T&} - item to be inserted * * @return std::pair<T*, bool> - {existing_item_address, false} iff item * already exists, {inserted_item_address, true} if item does not exist * */ void erase(const std::string& key) { //Convert key to bucket array index auto index = std::hash<std::string>{}(key)%Size;
  • 5. //Search for key auto prev = m_buckets[index]; auto next = prev; while( next != 0 ) { //If key found ... if(std::string((m_shared+next)->m_data)==key) { //delete found item if(prev==m_buckets[index]) m_buckets[index] = ((m_shared+prev)->m_next=(m_shared+next)->m_next); (m_shared+next)->m_next = *m_free; *m_free = next; } //Keep traversing linked list prev = next; next=(m_shared+next)->m_next; } } private: std::string m_key; unsigned* m_buckets; LinkedList* m_shared; unsigned* m_free; }; } /** * @} */ int main(void) { using namespace SharedMemoryContainers; //Raw Data struct RawData { unsigned m_user_id; unsigned m_dest_id; std::string m_branch; operator std::string(void) { return std::string(m_branch); } }; //Create a 100-bucket hash table const int buckets = 100; const int items = 5; typedef SharedMemoryHashTable<RawData, buckets, items> Table; Table shared_memory_hash_table(true); //Parent process unsigned user_id = 0; unsigned dest_id = 1000; //Insert values into shared memory hash table std::cout << "=====================================" << std::endl; std::cout << "Inserting values via parent process" << std::endl; //Loop over keys for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"})
  • 6. { //Insert item into hash table RawData raw_data = RawData{user_id++, dest_id--, str}; //str.copy(raw_data.m_branch, str.size()); if(str == "a") { shared_memory_hash_table.insert(raw_data.m_branch, raw_data); } else { shared_memory_hash_table[raw_data.m_branch]=raw_data; } std::cout << "hash_table[" << raw_data.m_branch << "]={" << raw_data.m_user_id << ", " << raw_data.m_dest_id << ", " << raw_data.m_branch << "}" << std::endl; //Validate insertion std::cout << "Verify: hash_table[" << raw_data.m_branch << "] == {" << shared_memory_hash_table[raw_data.m_branch].m_user_id << ", " << shared_memory_hash_table[raw_data.m_branch].m_dest_id << ", " << shared_memory_hash_table[raw_data.m_branch].m_branch << "}" << std::endl; } //Fork child process pid_t p_id = fork(); if (p_id == 0) { Table shared_memory_hash_table; //Extract values from shared memory hash table std::cout << "=====================================" << std::endl; std::cout << "Extracting values via child process" << std::endl; //Loop over keys for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"}) { //Find item for given key auto& item = shared_memory_hash_table[str.c_str()]; std::cout << "hash_table[" << str << "] == {" << item.m_user_id << ", " << item.m_dest_id << ", " << item.m_branch << "}" << std::endl; } std::cout << "=====================================" << std::endl; std::cout << "deleting key="bb" via child process" << std::endl; shared_memory_hash_table.erase("bb"); std::cout << "Extracting values left via child process" << std::endl; for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"}) { //Find item for given key auto item = shared_memory_hash_table.find(str.c_str()); if(item !=0) { std::cout << "hash_table[" << str << "] == {" << item->m_user_id << ", " << item->m_dest_id << ", " << item->m_branch << "}" << std::endl; } else { std::cout << str << " not found in hash table." << std::endl; }
  • 7. } std::cout << "=====================================" << std::endl; } else { int status; waitpid(p_id, &status, 0); std::cout << "=====================================" << std::endl; std::cout << "Extracting values left via parent process" << std::endl; for(std::string str : {"a", "bb", "ccc", "dddd", "eeeee"}) { //Find item for given key auto item = shared_memory_hash_table.find(str.c_str()); if(item !=0) { std::cout << "hash_table[" << str << "] == {" << item->m_user_id << ", " << item->m_dest_id << ", " << item->m_branch << "}" << std::endl; } else { std::cout << str << " not found in hash table." << std::endl; } } } return 0; }