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
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to