Hi,
I am actually working on a complex project which uses OSG 3.0.1 on a
Windows 7 Professional x64 SP1 platform with Visual Studio 2010
Premium SP1. Because I encountered random heap corruption errors, I
was testing and debugging with different configurations of my program
and could state the following:
- the invalid heap occurs mostly around one of the notification strings
- the problem occurs with all threading models except SingleThreaded
- the problem occurs still with an "empty" osg::NotifyHandler subclass
(which originally implements some custom logging mechanism)
- the problem occurs still without a custom osg::NotifyHandler
subclass, i.e. when using osg::StandardNotifyHandler by default
After all, I found the following forum thread which describes very
similar experiences:
http://forum.openscenegraph.org/viewtopic.php?t=9475 According to this
forum thread, I designed my custom osg::NotifyHandler subclass
thread-safe. Also, I checked out not to mix up incompatible binaries.
My actual working project is not portable. But in order to track the
problem on a non-Windows platform, I created another simple program
which is inspired by the forum thread mentioned above. Here it is:
#include <ctime>
#include <cstdlib>
#include <fstream>
#include <OpenThreads/Thread>
#include <osg/Notify>
// empty logging handler
class LogFileHandler : public osg::NotifyHandler
{
public:
LogFileHandler(const char *filename) { }
void notify(osg::NotifySeverity severity, const char *message) { }
protected:
~LogFileHandler() { }
};
// simple worker thread
class MyThread : public OpenThreads::Thread
{
public:
MyThread(int id)
: m_id(id)
{
OSG_INFO << "CREATE THREAD " << m_id << std::endl;
}
protected:
virtual void run()
{
int lines = 100000; // number of notifications generated by this thread
for (int i = 0; i < lines; ++i)
{
// generate a random notification, e.g. "HELLO FROM THREAD 2:
aaabbbcccccdde[...]zz..."
OSG_INFO << "HELLO FROM THREAD " << m_id << ": ";
int letters = 26;
for (int j = 0; j < letters; ++j)
{
char c = 'a' + j;
switch (std::rand() % 5 + 1)
{
case 1: OSG_INFO << c; break;
case 2: OSG_INFO << c << c; break;
case 3: OSG_INFO << c << c << c; break;
case 4: OSG_INFO << c << c << c << c; break;
case 5: OSG_INFO << c << c << c << c << c; break;
}
}
OSG_INFO << "..." << std::endl;
}
}
private:
int m_id;
};
// simple program
int main(int argc, char **argv)
{
srand(time(NULL));
osg::setNotifyLevel(osg::DEBUG_FP);
osg::setNotifyHandler(new LogFileHandler("log.txt")); // comment out
this line: stdout will contain mixed up strings
const int count = 2; // number of threads accessing the notification
API concurrently
MyThread *threads[count] = { };
for (int i = 0; i < count; ++i)
{
threads[i] = new MyThread(i);
threads[i]->start();
}
for (int i = 0; i < count; ++i)
{
while (threads[i]->isRunning()) { /* active wait until the worker
thread ends */ }
delete threads[i];
threads[i] = NULL;
}
return EXIT_SUCCESS;
}
The program essentially imitates a multi-threaded environment for the
notification API by creating some worker threads. Every thread
generates a bulk of random notifications and pushes them per OSG_INFO.
I think, one can compare this scenario with the case where a verbose
notify level is used in combination with a non-SingleThreaded
threading model, or am I wrong?
In my Win 7 x64 VS 2010 environment the result is the following: I got
frequent heap corruption errors. The problem can be reproduced more or
less depending on the number of concurrently running threads and if it
is a debug or release build. If I comment out the use of the custom
osg::NotifyHandler subclass (which defaults to
osg::StandardNotifyHandler), I recognized mixed up strings and missing
endl's in stdout.
Furthermore, I tested this program with Lubuntu 12.0.4 x64 and the
QtCreator from the QtSDK 4.8.1. At least in debug mode, I got frequent
heap corruption errors. If I comment out the use of the custom
osg::NotifyHandler subclass, I recognized mixed up strings (debug) and
missing endl's (debug and release) in stdout as well.
Concluding, for my actual working project I will run SingleThreaded to
avoid heap corruption as it fits my needs at the moment. But I cannot
overcome some questions:
- Do I miss some well-known restrictions, when using the notification
API with multi-threading?
- IMHO the heap corruption is caused by the non-thread-safe access to
the global static instance of osg::NotifyStream defined in Notify.cpp.
All over OSG, it is accessed by a reference to std::ostream which is
returned by the osg::notify() function in order to call operator << on
it. Can someone check these facts and explain to me, why there is no
locking mechanism or the like to make the stream thread-safe?
I appreciate every enlightenment or correction!
Matthias Schütze, Germany
_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org