POSIX shared memory is actually a variation of mapped memory. The major differences are to use shm_open() to open the shared memory object (instead of calling open()) and use shm_unlink() to close and delete the object (instead of calling close() which does not remove the object). The options in shm_open() are substantially fewer than the number of options provided in open().
IPC Shared Memory is an efficeint means of passing data between programs. One program will create a memory portion which other processes (if permitted) can access.
IMHO, the difference between them is not huge or even large since POSIX shared memory is just latter and more standard implementation of shared memory concept. The kill -9 problem is really problem. You cannot setup any handler and even atexit is not called. But you can set handler for SIGTERM and terminate your process with command:
kill -SIGTERM <pid>
Sample code for atexit and signal handler:
#include <signal.h>
#include <unistd.h>
#include <cerrno>
#include <system_error>
#include <iostream>
static sigset_t theMask;
static void
signalWrapper(
int theSignalNumber,
siginfo_t* theSignalDescription,
void* theUserContext)
{
if (theSignalNumber == SIGTERM)
{
std::cerr << "Clear shared memory and exit" << std::endl;
exit(1);
}
// Reinstall handler (usefull for other signals)
struct ::sigaction sa;
sa.sa_sigaction = &signalWrapper;
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
try
{
if (::sigaction(theSignalNumber, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
}
void
setupSignalHandlers()
{
struct ::sigaction sa;
// Prepare mask
sigemptyset(&theMask);
sigaddset(&theMask, SIGTERM);
// Add some more if you need it to process
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = &signalWrapper;
// Perform setup
try
{
if (::sigaction(SIGTERM, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
}
void
bye()
{
std::cout << "Bye!" << std::endl;
}
int
main()
{
std::cout << "Set handler!" << std::endl;
setupSignalHandlers();
if (std::atexit(bye))
{
std::cerr << "Failed to register atexit" << std::endl;
return 2;
}
std::cout << "Emit SIGTERM signals" << std::endl;
kill(getpid(), SIGTERM);
sleep(100);
return 0;
}
Another interesting approach is shm_unlink() right after shm_open() and use of O_CLOEXEC. I wrote small code sample to illustrate use of unlink and POSIX shared memory reopen:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <iostream>
// Simple ShMem with RAII
struct ShMem
{
ShMem(
const std::string& theName)
: _handle(-1),
_mode(S_IRUSR | S_IWUSR),
_name(theName)
{
// Here we try to create the object with exclusive right to it
// If the object exists - it must fail.
// File opened as 0600. The open mode might be set with
// class enum and additional paramter to constructor
if ((_handle = shm_open(_name.c_str(), O_CREAT | O_RDWR | O_EXCL, _mode)) < 0)
{
std::cerr << strerror(errno) << std::endl;
std::cout << "File " << _name << "exists. Try to reopen it!" << std::endl;
if ((_handle = shm_open(_name.c_str(), O_RDWR | O_TRUNC, _mode)) < 0)
{
std::cerr << strerror(errno) << std::endl;
throw std::error_code(errno, std::system_category());
}
else
std::cout << _name << " reopened OK";
}
else
std::cout << _name << " created OK";
// Unlink but keep descriptor
shm_unlink(_name.c_str());
}
~ShMem()
{
}
const int
handle()
{
return _handle;
}
private:
int _handle;
mode_t _mode;
std::string _name;
};
With O_CLOEXEC you can remove shm_unlink() at all and see what happens on kill -9 .
SIGKILL, which is whatkill -9raises - Drew McGowen