C++ callstack on windows access violation - c++

I have been trying to make a Windows application dump the callstack on the event of a crash (bad memory access or division by zero) or standard c++ exceptions.
I have build StackWalker and linked it into my application and compiled my application with /EHa.
#include "win/StackWalker.h"
extern int runapp(int argc, char **argv);
// The exception filter function:
LONG WINAPI ExpFilter(EXCEPTION_POINTERS* pExp, DWORD dwExpCode) {
StackWalker sw;
sw.ShowCallstack(GetCurrentThread(), pExp->ContextRecord);
return EXCEPTION_EXECUTE_HANDLER;
}
int main(int argc, char *argv[]) {
__try
{
return runapp(argc, argv);
}
__except (ExpFilter(GetExceptionInformation(), GetExceptionCode()))
{
}
}
The real program is started via runapp() since it is not possible to instantiate objects that require unwinding (destruction) directly inside a __try scope.
My problem is that nothing is caught when I force my program to crash using this code:
int *data1 = 0;
*data1 = 0;
In other words, it just crashes "normally"
Does anybody have a hint?

/EHa switch tells compiler that you want to handle SEH exceptions inside C++ try/catch block. In your code you use SEH exception handler instead. This is a working approach I am using:
dbgutils.h
#pragma once
#include <eh.h>
#include <windows.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <boost/optional.hpp>
#include "StackWalker.h"
class CSO3SEHException
{
public:
CSO3SEHException(unsigned int nCode, EXCEPTION_POINTERS* pEx);
std::string what();
std::string stack();
private:
std::string m_sWhat, m_sStack;
std::string seName(const unsigned int& nCode);
boost::optional<std::string> seInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx);
void seStack(EXCEPTION_POINTERS* pEx);
void seExceptionInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx);
};
class CCustomStackWalker : public StackWalker
{
public:
CCustomStackWalker(std::stringstream* ss);
protected:
virtual void OnOutput(LPCSTR szText);
private:
std::stringstream* m_sOut;
};
void _so3_seh_translate(unsigned int code, _EXCEPTION_POINTERS *ep);
void ReportSEHException(CSO3SEHException& ex);
dbgutils.cpp
#include "dbgutils.h"
CCustomStackWalker::CCustomStackWalker(std::stringstream* ss)
{
m_sOut = ss;
}
void CCustomStackWalker::OnOutput(LPCSTR szText)
{
size_t sLen = strlen(szText);
std::string s = std::string(szText, sLen);
(*m_sOut) << s << std::endl;
}
CSO3SEHException::CSO3SEHException(unsigned int nCode, EXCEPTION_POINTERS* pEx)
{
seExceptionInfo(nCode, pEx);
seStack(pEx);
}
std::string CSO3SEHException::what()
{
return(m_sWhat);
}
std::string CSO3SEHException::stack()
{
return(m_sStack);
}
std::string CSO3SEHException::seName(const unsigned int& nCode)
{
switch (nCode)
{
case EXCEPTION_ACCESS_VIOLATION: return ("Access Violation");
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return ("Range Check");
case EXCEPTION_BREAKPOINT: return ("Breakpoint");
case EXCEPTION_DATATYPE_MISALIGNMENT: return ("Datatype misaligment");
case EXCEPTION_ILLEGAL_INSTRUCTION: return ("Illegal instruction");
case EXCEPTION_INT_DIVIDE_BY_ZERO: return ("Divide by zero");
case EXCEPTION_INT_OVERFLOW: return ("Integer overflow");
case EXCEPTION_PRIV_INSTRUCTION: return ("Privileged instruction");
case EXCEPTION_STACK_OVERFLOW: return ("Stack overflow");
default: return("UNKNOWN EXCEPTION");
}
}
boost::optional<std::string> CSO3SEHException::seInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx)
{
std::stringstream ss;
if (EXCEPTION_ACCESS_VIOLATION == nCode)
{
ss << (pEx->ExceptionRecord->ExceptionInformation[0] ? "write " : " read");
ss << std::hex << std::setfill('0');
ss << " of address 0x" << std::setw(2*sizeof(void*)) << (unsigned)pEx->ExceptionRecord->ExceptionInformation[1];
return(ss.str());
}
return(nullptr);
}
void CSO3SEHException::seStack(EXCEPTION_POINTERS* pEx)
{
std::stringstream ss;
CCustomStackWalker sw(&ss);
sw.ShowCallstack(GetCurrentThread(), pEx->ContextRecord);
m_sStack = ss.str();
}
void CSO3SEHException::seExceptionInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx)
{
std::stringstream ss;
ss << seName(nCode);
ss << std::hex << std::setfill('0');
ss << " at 0x" << std::setw(2*sizeof(void*)) << pEx->ExceptionRecord->ExceptionAddress;
auto pSInfo = seInfo(nCode, pEx);
if (pSInfo)
ss << *pSInfo;
m_sWhat = ss.str();
}
void _so3_seh_translate(unsigned int code, _EXCEPTION_POINTERS *ep)
{
throw CSO3SEHException(code, ep);
}
void ReportSEHException(CSO3SEHException& ex)
{
std::string sError = ex.what();
std::string sStack = ex.stack();
//do some error reporting here
}
somewhere in your code:
//You have to call _set_se_translator in all threads
_set_se_translator(_so3_seh_translate);
try
{
//do something exception-prone
}
catch (CSO3SEHException & pSEH)
{
ReportSEHException(pSEH);
}
catch (std::exception& err)
{
//handle c++ exceptions
}

The following solution works cross-platform (with the inclusion of StackWalker). Unfortunately it only works across threads on posix systems.
If someone has a solution for catching crashes/exceptions in all threads on Windows please tell.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#ifdef WINDOWS_OS
#include <windows.h>
#include "StackWalker.h"
#include <DbgHelp.h>
#include <iostream>
void seg_handler(int sig)
{
unsigned int i;
void * stack[ 100 ];
unsigned short frames;
SYMBOL_INFO * symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize( process, NULL, TRUE );
frames = CaptureStackBackTrace( 0, 100, stack, NULL );
symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
for( i = 0; i < frames; i++ ) {
SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );
printf( "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address );
}
free( symbol );
StackWalker sw;
sw.ShowCallstack(GetCurrentThread());
exit(1);
}
void std_handler( void ) {
seg_handler(1);
}
#else
#include <execinfo.h>
#include <unistd.h>
void seg_handler(int sig) {
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
void std_handler( void )
{
void *trace_elems[20];
int trace_elem_count(backtrace( trace_elems, 20 ));
char **stack_syms(backtrace_symbols( trace_elems, trace_elem_count ));
for ( int i = 0 ; i < trace_elem_count ; ++i )
{
std::cout << stack_syms[i] << "\n";
}
free( stack_syms );
exit(1);
}
#endif
int main(int argc, char *argv[]) {
signal(SIGSEGV, seg_handler);
std::set_terminate( std_handler );
// Main Program
// Crash
int *a = 0;
*a = 1;
}

Related

boost interprocess message_queue and fork

I am trying to communicate with forked child process using message queue from boost interprocess library. When child process calls receive it causes exception with message
boost::interprocess_exception::library_error
I am using GCC 6.3 on Debian 9 x64.
#include <iostream>
#include <unistd.h>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <memory>
int main(int argc, char* argv[])
{
using namespace boost::interprocess;
const char* name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
const int max_num_msg = 100;
const int max_msg_size = 32;
bool is_child = false;
message_queue::remove(name);
auto mq = std::make_unique<message_queue>(create_only, name, max_num_msg, max_msg_size);
auto child_pid = fork();
if (child_pid == -1)
{
std::cout << "fork failed" << std::endl;
return -1;
}
else if (child_pid == 0)
{
is_child = true;
}
if (is_child)
{
// does child needs to reopen it?
mq.reset( new message_queue(open_only, name) );
}
int send_num = 0;
while(true)
{
unsigned int priority = 0;
if (is_child)
{
message_queue::size_type bytes = 0;
try
{
int num;
// Always throws. What is wrong ???????
mq->receive(&num, sizeof(num), bytes, priority);
std::cout << num << std::endl;
}
catch(const std::exception& e)
{
std::cout << "Receive caused execption " << e.what() << std::endl;
}
sleep(1);
}
else
{
mq->send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
return 0;
}
Also, in child process is it required to reopen the message queue created by the parent process? I tried it both ways and neither worked. I am getting the same exception on receive.
The problem is that your receive buffer is smaller than max_msg_size. Assuming 4-byte integers, this should work:
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
Also, I see no reason to play fast and loose with the actual queue instance. Just create it per process:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <iostream>
#include <memory>
#include <unistd.h>
int main() {
namespace bip = boost::interprocess;
const char *name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
{
const int max_num_msg = 100;
const int max_msg_size = 32;
bip::message_queue::remove(name);
bip::message_queue mq(bip::create_only, name, max_num_msg, max_msg_size);
}
auto child_pid = fork();
if (child_pid == -1) {
std::cout << "fork failed" << std::endl;
return -1;
}
bip::message_queue mq(bip::open_only, name);
if (bool const is_child = (child_pid == 0)) {
while (true) {
unsigned int priority = 0;
bip::message_queue::size_type bytes = 0;
try {
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
} catch (const bip::interprocess_exception &e) {
std::cout << "Receive caused execption " << boost::diagnostic_information(e, true) << std::endl;
}
sleep(1);
}
} else {
// parent
int send_num = 0;
while (true) {
unsigned int priority = 0;
mq.send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
}

C++ / Gcc - Stack smashing when a func returns a struct

I'm actually having troubles with a simple program which is supposed to pass a struct through named pipes.
Here is my main.cpp:
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <string>
#include "NamedPipe.hh"
int main()
{
pid_t pid;
std::string str("test_namedPipe");
NamedPipe pipe(str);
message *msg;
//Initialisation of my struct
msg = (message *)malloc(sizeof(message) + sizeof(char) * 12);
msg->type = 1;
sprintf(msg->str, "Hello World");
//Forking
pid = fork();
if (pid != 0) {
pipe.send(msg);
} else {
message msg_receive = pipe.receive(); //Here is the overflow
std::cout << "type: " << msg_receive.type << " file: " << msg_receive.str << std::endl;
}
return (0);
}
My NamedPipe.cpp:
#include "NamedPipe.hh"
#include <stdio.h>
NamedPipe::NamedPipe(std::string const &_name) : name("/tmp/" + _name) {
mkfifo(name.c_str(), 0666);
// std::cout << "create fifo " << name << std::endl;
}
NamedPipe::~NamedPipe() {
unlink(name.c_str());
}
void NamedPipe::send(message *msg) {
int fd;
int size = sizeof(char) * 12 + sizeof(message);
fd = open(name.c_str(), O_WRONLY);
write(fd, &size, sizeof(int));
write(fd, msg, (size_t)size);
close(fd);
}
message NamedPipe::receive() {
int fd;
int size;
message msg;
fd = open(name.c_str(), O_RDONLY);
read(fd, &size, sizeof(int));
read(fd, &msg, (size_t)size);
close(fd);
return (msg); //I debugged with printf. This actually reach this point before overflow
}
And my struct is defined like:
struct message {
int type;
char str[0];
};
I actually think that may be a problem of memory allocation, but I have really no idea of what I should do to fix this.
Thanks for reading/helping !
This is the root of your problem, your struct message:
char str[0];
This is not kosher in C++ (nor is the way you're using it kosher in C). When you allocate a message on the stack, you're allocating room for one int and 0 chars. Then in this line
read(fd, &msg, (size_t)size);
you write beyond your stack allocation into neverland. Then you return your message object which would be just one int in size.
Change your struct to this, and it should "work"
struct message
{
int type;
char str[ 16 ];
};

Why can't this program output the right exception?

The program below outputs only:
0In finally
And not the output:
0 In trans_func Caught a __try exception with SE_Exception In finally
As I expected.
#include "stdafx.h"
// crt_settrans.cpp
// compile with: /EHa
#include <stdio.h>
#include <windows.h>
#include <eh.h>
void SEFunc();
void trans_func( unsigned int, EXCEPTION_POINTERS* );
class SE_Exception
{
private:
unsigned int nSE;
public:
SE_Exception() {}
SE_Exception( unsigned int n ) : nSE( n ) {}
~SE_Exception() {}
unsigned int getSeNumber() { return nSE; }
};
int main( void )
{
try
{
_set_se_translator( trans_func );
SEFunc();
}
catch( SE_Exception e )
{
printf( "Caught a __try exception with SE_Exception.\n" );
}
system("pause");
}
void SEFunc()
{
__try
{
int* buffer= new int[19];
buffer[19]=0;
printf("%d",buffer[19]);
delete buffer;
}
__finally
{
printf( "In finally\n" );
}
}
void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
printf( "In trans_func.\n" );
throw SE_Exception();
}
trans_func will only be called in order to handle a structured exception.
But your code doesn't seem to trigger an SEH exception :
int* buffer= new int[19];
buffer[19]=0;
printf("%d",buffer[19]);
delete buffer;
Maybe you should try something a bit more brutal :
volatile int *pInt = 0x00000000;
*pInt = 20;
That example is directly taken from MSDN.

in the handler of SetUnhandledExceptionFilter how to print a stacktrace?

When unhandled exception occured i want to print a stacktrace instead of just terminating. I've tried to do that using SetUnhandledExceptionFilter:
SetUnhandledExceptionFilter(UnhandledException);
...
LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo)
{
printf("An exception occurred which wasn't handled!\nCode: 0x%08X\nAddress: 0x%08X",
exceptionInfo->ExceptionRecord->ExceptionCode,
exceptionInfo->ExceptionRecord->ExceptionAddress);
return EXCEPTION_EXECUTE_HANDLER;
}
This code, i've found, works fine. However there are no addition information because ExceptionCode and ExceptionAddress are printed in system "Event Viewer" anyway.
If it is possible to print a full stack trace so I can determine the exact point where exception occured?
I've found this code https://code.google.com/p/m0d-s0beit-sa/source/browse/src/main.cpp?r=9ceb4fec21d647b169c72851d7882bef2b9c5a8a It partly solves my problem. Only method where exception occured is printed. But type of exception and line number is not printed.
Here's some stack-walk code for Windows I wrote some years ago. Here's the kind of output it produces:
Walking stack.
0 DebugBreak
1 ThreadFunc2 e:\c\source\stackwalk2a.cpp(72)
2 ThreadFunc1 e:\c\source\stackwalk2a.cpp(79)
3 TargetThread e:\c\source\stackwalk2a.cpp(86)
4 BaseThreadInitThunk
5 RtlUserThreadStart
End of stack walk.
The main thing that's missing is anything about the exception type. If you're talking about a native structured/vectored exception, I'm pretty sure that should be retrievable too. Retrieving types of C++ exceptions might be a little more difficult (but I'm not really sure -- it might be pretty easy).
#include <windows.h>
#include <winnt.h>
#include <string>
#include <vector>
#include <Psapi.h>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <iterator>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
// Some versions of imagehlp.dll lack the proper packing directives themselves
// so we need to do it.
#pragma pack( push, before_imagehlp, 8 )
#include <imagehlp.h>
#pragma pack( pop, before_imagehlp )
struct module_data {
std::string image_name;
std::string module_name;
void *base_address;
DWORD load_size;
};
typedef std::vector<module_data> ModuleList;
HANDLE thread_ready;
bool show_stack(std::ostream &, HANDLE hThread, CONTEXT& c);
DWORD __stdcall TargetThread( void *arg );
void ThreadFunc1();
void ThreadFunc2();
DWORD Filter( EXCEPTION_POINTERS *ep );
void *load_modules_symbols( HANDLE hProcess, DWORD pid );
int main( void ) {
DWORD thread_id;
thread_ready = CreateEvent( NULL, false, false, NULL );
HANDLE thread = CreateThread( NULL, 0, TargetThread, NULL, 0, &thread_id );
WaitForSingleObject( thread_ready, INFINITE );
CloseHandle(thread_ready);
return 0;
}
// if you use C++ exception handling: install a translator function
// with set_se_translator(). In the context of that function (but *not*
// afterwards), you can either do your stack dump, or save the CONTEXT
// record as a local copy. Note that you must do the stack dump at the
// earliest opportunity, to avoid the interesting stack-frames being gone
// by the time you do the dump.
DWORD Filter(EXCEPTION_POINTERS *ep) {
HANDLE thread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &thread, 0, false, DUPLICATE_SAME_ACCESS);
std::cout << "Walking stack.";
show_stack(std::cout, thread, *(ep->ContextRecord));
std::cout << "\nEnd of stack walk.\n";
CloseHandle(thread);
return EXCEPTION_EXECUTE_HANDLER;
}
void ThreadFunc2() {
__try { DebugBreak(); }
__except (Filter(GetExceptionInformation())) { }
SetEvent(thread_ready);
}
void ThreadFunc1(void (*f)()) {
f();
}
// We'll do a few levels of calls from our thread function so
// there's something on the stack to walk...
//
DWORD __stdcall TargetThread(void *) {
ThreadFunc1(ThreadFunc2);
return 0;
}
class SymHandler {
HANDLE p;
public:
SymHandler(HANDLE process, char const *path=NULL, bool intrude = false) : p(process) {
if (!SymInitialize(p, path, intrude))
throw(std::logic_error("Unable to initialize symbol handler"));
}
~SymHandler() { SymCleanup(p); }
};
#ifdef _M_X64
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Rip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Rsp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Rbp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#else
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Eip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Esp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Ebp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#endif
void sym_options(DWORD add, DWORD remove=0) {
DWORD symOptions = SymGetOptions();
symOptions |= add;
symOptions &= ~remove;
SymSetOptions(symOptions);
}
class symbol {
typedef IMAGEHLP_SYMBOL64 sym_type;
sym_type *sym;
static const int max_name_len = 1024;
public:
symbol(HANDLE process, DWORD64 address) : sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) {
memset(sym, '\0', sizeof(*sym) + max_name_len);
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLength = max_name_len;
DWORD64 displacement;
if (!SymGetSymFromAddr64(process, address, &displacement, sym))
throw(std::logic_error("Bad symbol"));
}
std::string name() { return std::string(sym->Name); }
std::string undecorated_name() {
std::vector<char> und_name(max_name_len);
UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE);
return std::string(&und_name[0], strlen(&und_name[0]));
}
};
bool show_stack(std::ostream &os, HANDLE hThread, CONTEXT& c) {
HANDLE process = GetCurrentProcess();
int frame_number=0;
DWORD offset_from_symbol=0;
IMAGEHLP_LINE64 line = {0};
SymHandler handler(process);
sym_options(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
void *base = load_modules_symbols(process, GetCurrentProcessId());
STACKFRAME64 s = init_stack_frame(c);
line.SizeOfStruct = sizeof line;
IMAGE_NT_HEADERS *h = ImageNtHeader(base);
DWORD image_type = h->FileHeader.Machine;
do {
if (!StackWalk64(image_type, process, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
return false;
os << std::setw(3) << "\n" << frame_number << "\t";
if ( s.AddrPC.Offset != 0 ) {
std::cout << symbol(process, s.AddrPC.Offset).undecorated_name();
if (SymGetLineFromAddr64( process, s.AddrPC.Offset, &offset_from_symbol, &line ) )
os << "\t" << line.FileName << "(" << line.LineNumber << ")";
}
else
os << "(No Symbols: PC == 0)";
++frame_number;
} while (s.AddrReturn.Offset != 0);
return true;
}
class get_mod_info {
HANDLE process;
static const int buffer_length = 4096;
public:
get_mod_info(HANDLE h) : process(h) {}
module_data operator()(HMODULE module) {
module_data ret;
char temp[buffer_length];
MODULEINFO mi;
GetModuleInformation(process, module, &mi, sizeof(mi));
ret.base_address = mi.lpBaseOfDll;
ret.load_size = mi.SizeOfImage;
GetModuleFileNameEx(process, module, temp, sizeof(temp));
ret.image_name = temp;
GetModuleBaseName(process, module, temp, sizeof(temp));
ret.module_name = temp;
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
return ret;
}
};
void *load_modules_symbols(HANDLE process, DWORD pid) {
ModuleList modules;
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
module_handles.resize(cbNeeded/sizeof(HMODULE));
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process));
return modules[0].base_address;
}

How to use Boost.Interprocess to stream data to other applications?

The main application needs to update the shared memory at a fast frequency.
And several consuming applications need to read from the shared memory to update the streamed data.
main and consuming applications are different processes.
How to implement this with Boost.Interprocess ?
producer:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/thread.hpp>
#include <iostream>
struct shared_data_t {
boost::uint32_t data;
boost::interprocess::interprocess_mutex mutex;
};
/***************************************************************************/
/* producer */
int main(int argc, char** argv) {
const char* shname = "_unique_object_name_";
boost::shared_ptr<const char> remover(
shname,
boost::interprocess::shared_memory_object::remove
);
try {
boost::interprocess::shared_memory_object shared_object(
boost::interprocess::create_only,
shname,
boost::interprocess::read_write
);
shared_object.truncate(sizeof(shared_data_t));
boost::interprocess::mapped_region region(
shared_object,
boost::interprocess::read_write
);
shared_data_t* data = new(region.get_address())shared_data_t;
assert(data);
const boost::uint32_t count = 0x1000;
for ( boost::uint32_t idx = 0; idx < count; ++idx ) {
{ boost::interprocess::scoped_lock<
boost::interprocess::interprocess_mutex
> lock(data->mutex);
data->data = idx;
}
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
} catch(boost::interprocess::interprocess_exception &e){
std::cout << e.what() << std::endl;
return 1;
}
return 0;
}
consumer:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/thread.hpp>
struct shared_data_t {
boost::uint32_t data;
boost::interprocess::interprocess_mutex mutex;
};
/***************************************************************************/
/* consumer */
int main(int argc, char** argv) {
try {
boost::interprocess::shared_memory_object shared_object(
boost::interprocess::open_only,
"_unique_object_name_",
boost::interprocess::read_only
);
shared_object.truncate(sizeof(shared_data_t));
boost::interprocess::mapped_region region(
shared_object,
boost::interprocess::read_only
);
shared_data_t* data = new(region.get_address())shared_data_t;
assert(data);
while ( true ) {
{ boost::interprocess::scoped_lock<
boost::interprocess::interprocess_mutex
> lock(data->mutex);
std::cout << "ping: " << data->data << std::endl;
}
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
} catch(boost::interprocess::interprocess_exception &e){
std::cout << e.what() << std::endl;
return 1;
}
return 0;
}
man:
http://www.boost.org/doc/libs/1_43_0/doc/html/interprocess/synchronization_mechanisms.html