Discussion:
[Opensg-users] MultiDisplayWindow and threads
Victor Haefner
2014-09-25 19:35:50 UTC
Permalink
Hi all,

I am trying to parellelize the rendering of all my Windows.
The first step towards this is to render in another thread:

Main thread:

...
// RenderActionRefPtr ract
BarrierRefPtr barrier = Barrier::get("MDW", true);
if (barrier->getNumWaiting() == 1) {
barrier->enter(2);
barrier->enter(2);
}
...

Second thread

int tries = 0;
bool state = INITIALIZING;
bool VRMultiWindow::init_win(const std::string &msg, const std::string
&server, Real32 progress) {
if (progress == 1) { state = CONNECTED; return true; }
if (tries == 3) { state = NO_CONNECTION; return false; }
tries++;
return true;
}

...
MultiDisplayWindowRefPtr win;
void initialize(RenderActionRefPtr ract) {
state = CONNECTING;
win = MultiDisplayWindow::create();

win->setSize(300, 300);
win->setHServers(1);
win->setVServers(1);
win->editMFServers()->push_back("localhost");

Thread::getCurrentChangeList()->commitChangesAndClear();
Thread::getCurrentChangeList()->fillFromCurrentState();

ClusterWindow::ConnectionCB cb = boost::bind(&VRMultiWindow::init_win,
this, _1, _2, _3);
win->initAsync(cb);
if (state == CONNECTED) win->render(ract);
}

update() {
ExternalThreadRefPtr tr = OSGThread::create("update", 0);
tr->initialize(0); // same aspect as main frame, should be fine I hope
(main thread is waiting)

do {
BarrierRefPtr barrier = Barrier::get("MDW", true);
barrier->enter(2);

//Thread::getCurrentChangeList()->fillFromCurrentState(); // using
this line works somehow, at least the scene gets distributed..
ThreadRefPtr appThread = dynamic_cast<Thread
*>(ThreadManager::getAppThread());
ChangeList* cl = Thread::getCurrentChangeList();
ChangeList* acl = appThread->getChangeList();

cl->merge(*acl);

if (state == INITIALIZING) initialize(action);
else if (state == CONNECTED) {
try { win->render(action); }
catch(exception e) { state = INITIALIZING; }
}

Thread::getCurrentChangeList()->clear();
barrier->enter(2);

osgSleep(1);
} while(control_flag);

}

start update as a boost thread
...

I see nothing on the cluster client and I get this output:
...
WARNING: New container type 'GeoPnt3fProperty' local id '6476' remote id
'1100' dies because of missing ref counts.
WARNING: New container type 'GeoVec3fProperty' local id '6477' remote id
'1101' dies because of missing ref counts.
WARNING: New container type 'GeoVec2fProperty' local id '6478' remote id
'1102' dies because of missing ref counts.
WARNING: New container type 'GeoUInt32Property' local id '6479' remote id
'1103' dies because of missing ref counts.
WARNING: New container type 'GeoUInt32Property' local id '6480' remote id
'1104' dies because of missing ref counts.
WARNING: New container type 'GeoUInt8Property' local id '6481' remote id
'1105' dies because of missing ref counts.
WARNING: New container type 'Name' local id '6484' remote id '1108' dies
because of missing ref counts.
WARNING: New container type 'Name' local id '6486' remote id '1111' dies
because of missing ref counts.
WARNING: New container type 'GeoPnt3fProperty' local id '6488' remote id
'1113' dies because of missing ref counts.
WARNING: New container type 'GeoVec3fProperty' local id '6489' remote id
'1114' dies because of missing ref counts.
WARNING: New container type 'GeoVec2fProperty' local id '6490' remote id
'1115' dies because of missing ref counts.
WARNING: New container type 'GeoUInt32Property' local id '6491' remote id
'1116' dies because of missing ref counts.
WARNING: New container type 'GeoUInt32Property' local id '6492' remote id
'1117' dies because of missing ref counts.
WARNING: New container type 'GeoUInt8Property' local id '6493' remote id
'1118' dies because of missing ref counts.
WARNING: New container type 'Name' local id '6496' remote id '1121' dies
because of missing ref counts.
WARNING: New container type 'Name' local id '6498' remote id '1124' dies
because of missing ref counts.
WARNING: New container type 'GeoPnt3fProperty' local id '6500' remote id
'1126' dies because of missing ref counts.
WARNING: New container type 'GeoVec3fProperty' local id '6501' remote id
'1127' dies because of missing ref counts.
WARNING: New container type 'GeoVec2fProperty' local id '6502' remote id
'1128' dies because of missing ref counts.
WARNING: New container type 'GeoUInt32Property' local id '6503' remote id
'1129' dies because of missing ref counts.
WARNING: New container type 'GeoUInt32Property' local id '6504' remote id
'1130' dies because of missing ref counts.
WARNING: New container type 'GeoUInt8Property' local id '6505' remote id
'1131' dies because of missing ref counts.
WARNING: New container type 'Name' local id '6508' remote id '1134' dies
because of missing ref counts.
...

I think I am doing something wrong when merging the changelists..

I also did not fully understand what committing a changelist does.

Any ideas why the refcount is 'missing' ??

Many thanks and best Regards,
Victor
Carsten Neumann
2014-09-26 08:55:44 UTC
Permalink
Hello Victor,
Post by Victor Haefner
...
WARNING: New container type 'GeoPnt3fProperty' local id '6476' remote id
'1100' dies because of missing ref counts.
WARNING: New container type 'GeoVec3fProperty' local id '6477' remote id
'1101' dies because of missing ref counts.
[SNIP]
Post by Victor Haefner
Any ideas why the refcount is 'missing' ??
I haven't had a chance to look at/think about the code you've posted.
These warnings mean that the machine received the information that a new
FieldContainer was created, but the changes sent to the machine did not
contain any info about a ref count increase. That means at the end of
processing the received changes the container has zero references and
thus is destroyed (containers are kept 'artificially' alive for the
duration of the sync but not longer).
Post by Victor Haefner
I think I am doing something wrong when merging the changelists..
I also did not fully understand what committing a changelist does.
The CL serves two (related) purposes. The first is entirely unrelated to
multi-threading or clusters: changes are recorded (which FC and which
Fields of the FC) and when calling OSG::commitChanges() the changed()
member function of modified FCs is called so that they can update
internal state that depends on the changed fields. Changes that are
recorded but for which commitChanges() was not called yet are
'uncommitted' changes, afterwards they are 'committed' changes.

The second purpose is to be able to transfer changes to a different
aspect copy (local or remote) of an FC. Therefore commitChanges() does
not throw away the change record, but keeps it until the CL is cleared
(for single thread, non-cluster apps it can be done in one call:
commitChangesAndClear()). In a threaded/cluster application you would
usually clear the CL right after merging it to the destination
aspect/sending it over the network - that way you don't loose changes
and avoid applying them twice.

Hope the above helps, cheers,
Carsten
Victor Haefner
2014-09-26 20:43:21 UTC
Permalink
Hi Carsten,

thanks for those clarifications about changelists, but I still am confused
about the difference between commit and apply.
I made a standalone working example of my problem (c++11), my next step
will be to merge it in my project.. hope it will work :)
this needs two cluster multicast clients 'l1' and 'l2', hope it will be
useful to someone, any feedback is welcome.

Thanks and best regards,
Victor

#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGSimpleGeometry.h>
#include <OpenSG/OSGGLUTWindow.h>
#include <OpenSG/OSGPerspectiveCamera.h>
#include <OpenSG/OSGSimpleSceneManager.h>
#include <OpenSG/OSGSolidBackground.h>
#include <OpenSG/OSGPointLight.h>
#include <OpenSG/OSGMultiDisplayWindow.h>
#include <boost/thread/thread.hpp>
#include <boost/thread.hpp>

#include <OpenSG/OSGChangeList.h>
#include <OpenSG/OSGThread.h>
#include <OpenSG/OSGThreadManager.h>

OSG_USING_NAMESPACE;
using namespace std;

enum STATE {
NO_CONNECTION = 0,
CONNECTED = 1,
INITIALIZING = 2,
CONNECTING = 3
};

GLUTWindowRecPtr gwin;
TransformRecPtr trans;
RenderActionRefPtr ract;
ViewportRecPtr vp2;
ViewportRecPtr vp3;
int N = 1;

class OSGThread : public ExternalThread {
public:
static ExternalThread* create(const char* szName, int uiId) {
return ExternalThread::create(szName, uiId);
}
};

class MultiWindow {
private:
boost::thread* thread = 0;
int tries = 0;
string server;
ViewportRecPtr vp;
STATE state = INITIALIZING;
MultiDisplayWindowRecPtr mwin;

public:
MultiWindow(string s, ViewportRecPtr vp) {
N++;
server = s;
this->vp = vp;
thread = new boost::thread(boost::bind(&MultiWindow::update,
this));
}

bool init_win(const std::string &msg, const std::string &server,
Real32 progress) {
if (progress == 1) { state = CONNECTED; return true; }
if (tries == 3) { state = NO_CONNECTION; return false; }
tries++;
return true;
}

void initialize(RenderActionRefPtr ract) {
cout << "Initializing\n";
state = CONNECTING;
mwin = MultiDisplayWindow::create();

mwin->setSize(300, 300);
mwin->setHServers(1);
mwin->setVServers(1);
mwin->editMFServers()->push_back(server.c_str());
mwin->addPort(vp);

Thread::getCurrentChangeList()->commitChangesAndClear();
Thread::getCurrentChangeList()->fillFromCurrentState();

ClusterWindow::ConnectionCB cb =
boost::bind(&MultiWindow::init_win, this, _1, _2, _3);
mwin->initAsync(cb);
cout << " done\n";
}

void update() {
ExternalThreadRefPtr tr = OSGThread::create("update", 0);
tr->initialize(0);

sleep(3);

do {
BarrierRefPtr barrier = Barrier::get("MDW", true);
barrier->enter(N);

ThreadRefPtr appThread =
dynamic_cast<Thread*>(ThreadManager::getAppThread());
ChangeList* cl = Thread::getCurrentChangeList();
ChangeList* acl = appThread->getChangeList();
cl->merge(*acl);

if (state == INITIALIZING) initialize(ract);
if (state == CONNECTED) {
try { mwin->render(ract); }
catch(exception e) { state = INITIALIZING; }
}

Thread::getCurrentChangeList()->clear();
barrier->enter(N);

osgSleep(1);
} while(true);
}
};

void reshape(int w, int h) { gwin->resize(w, h); glutPostRedisplay(); }
void display(void) {
OSG::Matrix m;
OSG::Real32 time = glutGet(GLUT_ELAPSED_TIME );
m.setRotate(OSG::Quaternion(OSG::Vec3f(0,1,0), time/300.f));
m.setTranslate(Vec3f(0,0,-1));
trans->setMatrix(m);
commitChanges();

gwin->render(ract);

BarrierRefPtr barrier = Barrier::get("MDW", true);
if (barrier->getNumWaiting() == N-1) {
barrier->enter(N);
barrier->enter(N);
}

Thread::getCurrentChangeList()->clear();
}


int main(int argc, char **argv) {
glutInit(&argc, argv);
glEnable(GL_DEPTH_TEST);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
ChangeList::setReadWriteDefault();
osgInit(argc,argv);
int winid = glutCreateWindow("MW test");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(display);
gwin = GLUTWindow::create();
gwin->setGlutId(winid);
gwin->init();
ract = RenderAction::create();

trans = Transform::create();
NodeRecPtr l = makeNodeFor(PointLight::create());
NodeRecPtr t = makeNodeFor(trans);
NodeRecPtr cb = makeNodeFor(Transform::create());
NodeRecPtr g = makeTeapot(4, 0.1);
PerspectiveCameraRecPtr c = PerspectiveCamera::create();
SolidBackgroundRecPtr bg = SolidBackground::create();
l->addChild(cb);
l->addChild(t);
t->addChild(g);
c->setBeacon(cb);
c->setFov(osgDegree2Rad(60));
c->setNear(0.1);
c->setFar(10);

ViewportRecPtr vp = Viewport::create();
gwin->addPort(vp);
vp->setRoot(l);
vp->setCamera(c);
vp->setBackground(bg);

vp2 = Viewport::create();
vp2->setRoot(l);
vp2->setCamera(c);
vp2->setBackground(bg);

vp3 = Viewport::create();
vp3->setRoot(l);
vp3->setCamera(c);
vp3->setBackground(bg);

MultiWindow* mv1 = new MultiWindow("l1", vp2);
MultiWindow* mv2 = new MultiWindow("l2", vp3);

glutMainLoop();

return 0;
}

On Fri, Sep 26, 2014 at 10:55 AM, Carsten Neumann <
Post by Carsten Neumann
Hello Victor,
Post by Victor Haefner
...
WARNING: New container type 'GeoPnt3fProperty' local id '6476' remote id
'1100' dies because of missing ref counts.
WARNING: New container type 'GeoVec3fProperty' local id '6477' remote id
'1101' dies because of missing ref counts.
[SNIP]
Post by Victor Haefner
Any ideas why the refcount is 'missing' ??
I haven't had a chance to look at/think about the code you've posted.
These warnings mean that the machine received the information that a new
FieldContainer was created, but the changes sent to the machine did not
contain any info about a ref count increase. That means at the end of
processing the received changes the container has zero references and
thus is destroyed (containers are kept 'artificially' alive for the
duration of the sync but not longer).
Post by Victor Haefner
I think I am doing something wrong when merging the changelists..
I also did not fully understand what committing a changelist does.
The CL serves two (related) purposes. The first is entirely unrelated to
multi-threading or clusters: changes are recorded (which FC and which
Fields of the FC) and when calling OSG::commitChanges() the changed()
member function of modified FCs is called so that they can update
internal state that depends on the changed fields. Changes that are
recorded but for which commitChanges() was not called yet are
'uncommitted' changes, afterwards they are 'committed' changes.
The second purpose is to be able to transfer changes to a different
aspect copy (local or remote) of an FC. Therefore commitChanges() does
not throw away the change record, but keeps it until the CL is cleared
commitChangesAndClear()). In a threaded/cluster application you would
usually clear the CL right after merging it to the destination
aspect/sending it over the network - that way you don't loose changes
and avoid applying them twice.
Hope the above helps, cheers,
Carsten
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
_______________________________________________
Opensg-users mailing list
https://lists.sourceforge.net/lists/listinfo/opensg-users
Victor Haefner
2014-09-27 20:05:28 UTC
Permalink
Hi,

I got it to work, I think it was that I had to commit changes in the main
Thread before rendering and not afterwards.

thanks and best regards,
Victor
Post by Victor Haefner
Hi Carsten,
thanks for those clarifications about changelists, but I still am confused
about the difference between commit and apply.
I made a standalone working example of my problem (c++11), my next step
will be to merge it in my project.. hope it will work :)
this needs two cluster multicast clients 'l1' and 'l2', hope it will be
useful to someone, any feedback is welcome.
Thanks and best regards,
Victor
#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGSimpleGeometry.h>
#include <OpenSG/OSGGLUTWindow.h>
#include <OpenSG/OSGPerspectiveCamera.h>
#include <OpenSG/OSGSimpleSceneManager.h>
#include <OpenSG/OSGSolidBackground.h>
#include <OpenSG/OSGPointLight.h>
#include <OpenSG/OSGMultiDisplayWindow.h>
#include <boost/thread/thread.hpp>
#include <boost/thread.hpp>
#include <OpenSG/OSGChangeList.h>
#include <OpenSG/OSGThread.h>
#include <OpenSG/OSGThreadManager.h>
OSG_USING_NAMESPACE;
using namespace std;
enum STATE {
NO_CONNECTION = 0,
CONNECTED = 1,
INITIALIZING = 2,
CONNECTING = 3
};
GLUTWindowRecPtr gwin;
TransformRecPtr trans;
RenderActionRefPtr ract;
ViewportRecPtr vp2;
ViewportRecPtr vp3;
int N = 1;
class OSGThread : public ExternalThread {
static ExternalThread* create(const char* szName, int uiId) {
return ExternalThread::create(szName, uiId);
}
};
class MultiWindow {
boost::thread* thread = 0;
int tries = 0;
string server;
ViewportRecPtr vp;
STATE state = INITIALIZING;
MultiDisplayWindowRecPtr mwin;
MultiWindow(string s, ViewportRecPtr vp) {
N++;
server = s;
this->vp = vp;
thread = new boost::thread(boost::bind(&MultiWindow::update,
this));
}
bool init_win(const std::string &msg, const std::string &server,
Real32 progress) {
if (progress == 1) { state = CONNECTED; return true; }
if (tries == 3) { state = NO_CONNECTION; return false; }
tries++;
return true;
}
void initialize(RenderActionRefPtr ract) {
cout << "Initializing\n";
state = CONNECTING;
mwin = MultiDisplayWindow::create();
mwin->setSize(300, 300);
mwin->setHServers(1);
mwin->setVServers(1);
mwin->editMFServers()->push_back(server.c_str());
mwin->addPort(vp);
Thread::getCurrentChangeList()->commitChangesAndClear();
Thread::getCurrentChangeList()->fillFromCurrentState();
ClusterWindow::ConnectionCB cb =
boost::bind(&MultiWindow::init_win, this, _1, _2, _3);
mwin->initAsync(cb);
cout << " done\n";
}
void update() {
ExternalThreadRefPtr tr = OSGThread::create("update", 0);
tr->initialize(0);
sleep(3);
do {
BarrierRefPtr barrier = Barrier::get("MDW", true);
barrier->enter(N);
ThreadRefPtr appThread =
dynamic_cast<Thread*>(ThreadManager::getAppThread());
ChangeList* cl = Thread::getCurrentChangeList();
ChangeList* acl = appThread->getChangeList();
cl->merge(*acl);
if (state == INITIALIZING) initialize(ract);
if (state == CONNECTED) {
try { mwin->render(ract); }
catch(exception e) { state = INITIALIZING; }
}
Thread::getCurrentChangeList()->clear();
barrier->enter(N);
osgSleep(1);
} while(true);
}
};
void reshape(int w, int h) { gwin->resize(w, h); glutPostRedisplay(); }
void display(void) {
OSG::Matrix m;
OSG::Real32 time = glutGet(GLUT_ELAPSED_TIME );
m.setRotate(OSG::Quaternion(OSG::Vec3f(0,1,0), time/300.f));
m.setTranslate(Vec3f(0,0,-1));
trans->setMatrix(m);
commitChanges();
gwin->render(ract);
BarrierRefPtr barrier = Barrier::get("MDW", true);
if (barrier->getNumWaiting() == N-1) {
barrier->enter(N);
barrier->enter(N);
}
Thread::getCurrentChangeList()->clear();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glEnable(GL_DEPTH_TEST);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
ChangeList::setReadWriteDefault();
osgInit(argc,argv);
int winid = glutCreateWindow("MW test");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(display);
gwin = GLUTWindow::create();
gwin->setGlutId(winid);
gwin->init();
ract = RenderAction::create();
trans = Transform::create();
NodeRecPtr l = makeNodeFor(PointLight::create());
NodeRecPtr t = makeNodeFor(trans);
NodeRecPtr cb = makeNodeFor(Transform::create());
NodeRecPtr g = makeTeapot(4, 0.1);
PerspectiveCameraRecPtr c = PerspectiveCamera::create();
SolidBackgroundRecPtr bg = SolidBackground::create();
l->addChild(cb);
l->addChild(t);
t->addChild(g);
c->setBeacon(cb);
c->setFov(osgDegree2Rad(60));
c->setNear(0.1);
c->setFar(10);
ViewportRecPtr vp = Viewport::create();
gwin->addPort(vp);
vp->setRoot(l);
vp->setCamera(c);
vp->setBackground(bg);
vp2 = Viewport::create();
vp2->setRoot(l);
vp2->setCamera(c);
vp2->setBackground(bg);
vp3 = Viewport::create();
vp3->setRoot(l);
vp3->setCamera(c);
vp3->setBackground(bg);
MultiWindow* mv1 = new MultiWindow("l1", vp2);
MultiWindow* mv2 = new MultiWindow("l2", vp3);
glutMainLoop();
return 0;
}
On Fri, Sep 26, 2014 at 10:55 AM, Carsten Neumann <
Post by Carsten Neumann
Hello Victor,
Post by Victor Haefner
...
WARNING: New container type 'GeoPnt3fProperty' local id '6476' remote id
'1100' dies because of missing ref counts.
WARNING: New container type 'GeoVec3fProperty' local id '6477' remote id
'1101' dies because of missing ref counts.
[SNIP]
Post by Victor Haefner
Any ideas why the refcount is 'missing' ??
I haven't had a chance to look at/think about the code you've posted.
These warnings mean that the machine received the information that a new
FieldContainer was created, but the changes sent to the machine did not
contain any info about a ref count increase. That means at the end of
processing the received changes the container has zero references and
thus is destroyed (containers are kept 'artificially' alive for the
duration of the sync but not longer).
Post by Victor Haefner
I think I am doing something wrong when merging the changelists..
I also did not fully understand what committing a changelist does.
The CL serves two (related) purposes. The first is entirely unrelated to
multi-threading or clusters: changes are recorded (which FC and which
Fields of the FC) and when calling OSG::commitChanges() the changed()
member function of modified FCs is called so that they can update
internal state that depends on the changed fields. Changes that are
recorded but for which commitChanges() was not called yet are
'uncommitted' changes, afterwards they are 'committed' changes.
The second purpose is to be able to transfer changes to a different
aspect copy (local or remote) of an FC. Therefore commitChanges() does
not throw away the change record, but keeps it until the CL is cleared
commitChangesAndClear()). In a threaded/cluster application you would
usually clear the CL right after merging it to the destination
aspect/sending it over the network - that way you don't loose changes
and avoid applying them twice.
Hope the above helps, cheers,
Carsten
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
_______________________________________________
Opensg-users mailing list
https://lists.sourceforge.net/lists/listinfo/opensg-users
Carsten Neumann
2014-09-29 12:48:35 UTC
Permalink
Hello Victor,
Post by Victor Haefner
I got it to work, I think it was that I had to commit changes in the
main Thread before rendering and not afterwards.
glad to hear it. Yes, the commit should happen before rendering/merging
your changelists elsewhere, that way side effects of a change are
applied together with the change that caused them.

Cheers,
Carsten

Loading...