Commit e058294f authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum

[CHANGE] - now the data loading is asynchronous but keeps the order

parent 2074992c
......@@ -25,6 +25,7 @@
#include <iostream>
#include "WConditionOneShot.h"
#include "../common/WLogger.h"
#include "WThreadedRunner.h"
......@@ -48,6 +49,11 @@ void WThreadedRunner::run()
m_Thread = new boost::thread( boost::bind( &WThreadedRunner::threadMain, this ) );
}
void WThreadedRunner::run( THREADFUNCTION f )
{
m_Thread = new boost::thread( f );
}
void WThreadedRunner::wait( bool requestFinish )
{
if( requestFinish )
......@@ -69,6 +75,7 @@ void WThreadedRunner::waitForStop()
void WThreadedRunner::threadMain()
{
WLogger::getLogger()->addLogMessage( "This should never be called. Implement a thread function here.", "WThreadedRunner", LL_WARNING );
}
void WThreadedRunner::notifyStop()
......
......@@ -27,6 +27,7 @@
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
#include "WFlag.h"
......@@ -37,6 +38,11 @@ class WThreadedRunner
{
public:
/**
* Type used for simple thread functions.
*/
typedef boost::function< void ( void ) > THREADFUNCTION;
/**
* Default constructor.
*/
......@@ -50,7 +56,12 @@ public:
/**
* Run thread.
*/
void run();
virtual void run();
/**
* Run thread. This does not start threadMain(() but runs a specified function instead.
*/
void run( THREADFUNCTION f );
/**
* Wait for the thread to be finished.
......
......@@ -129,7 +129,7 @@ int WQt4Gui::run()
m_mainWindow = new WMainWindow();
m_mainWindow->show();
// connect out loader signal with krnel
// connect out loader signal with kernel
getLoadButtonSignal()->connect( boost::bind( &WKernel::loadDataSets, m_kernel, _1 ) );
m_mainWindow->getModuleButtonSignal()->connect( boost::bind( &WKernel::applyModule, m_kernel, _1, _2 ) );
......
......@@ -212,7 +212,7 @@ WQtDatasetTreeItem* WQtDatasetBrowser::addDataset( boost::shared_ptr< WModule >
WQtSubjectTreeItem* subject = ( WQtSubjectTreeItem* )m_treeWidget->topLevelItem( subjectId + 1 );
subject->setExpanded( true );
WQtDatasetTreeItem* item = subject->addDatasetItem( module );
item->setDisabled( false );
item->setDisabled( true );
return item;
}
......@@ -419,7 +419,7 @@ std::vector< boost::shared_ptr< WDataSet > > WQtDatasetBrowser::getDataSetList(
boost::shared_ptr< WMData > dm = boost::shared_dynamic_cast< WMData >( ( ( WQtDatasetTreeItem* )m_treeWidget->invisibleRootItem()->child(
subjectId + 1 )->child( i ) )->getModule() );
if ( !onlyTextures || dm->getDataSet()->isTexture() )
if ( dm->isReady()() && ( !onlyTextures || dm->getDataSet()->isTexture() ) )
{
if ( dm->getProperties()->getValue<bool>( "active" ) )
{
......
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <iostream>
#include "WModuleContainer.h"
#include "WModule.h"
#include "WModuleFactory.h"
#include "WBatchLoader.h"
WBatchLoader::WBatchLoader( std::vector< std::string > fileNames, boost::shared_ptr< WModuleContainer > targetContainer ):
WThreadedRunner(),
boost::enable_shared_from_this< WBatchLoader >(),
m_fileNamesToLoad( fileNames ),
m_targetContainer( targetContainer )
{
// initialize members
}
WBatchLoader::~WBatchLoader()
{
// cleanup
}
void WBatchLoader::run()
{
// the module needs to be add here, as it else could be freed before the thread finishes ( remember: it is a shared_ptr).
m_targetContainer->addPendingThread( shared_from_this() );
// actually run
WThreadedRunner::run();
}
void WBatchLoader::threadMain()
{
// add a new data module for each file to load
for( std::vector< std::string >::iterator iter = m_fileNamesToLoad.begin(); iter != m_fileNamesToLoad.end(); ++iter )
{
boost::shared_ptr< WModule > mod = WModuleFactory::getModuleFactory()->create(
WModuleFactory::getModuleFactory()->getPrototypeByName( "Data Module" )
);
mod->getProperties()->setValue( "filename" , ( *iter ) );
m_targetContainer->add( mod );
// serialize loading of a couple of data sets
mod->isReady().wait();
}
m_targetContainer->finishedPendingThread( shared_from_this() );
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WBATCHLOADER_H
#define WBATCHLOADER_H
#include <iostream>
#include <boost/shared_ptr.hpp>
#include "../common/WThreadedRunner.h"
class WModuleContainer;
/**
* Class for loading many datasets. It runs in a separate thread.
*/
class WBatchLoader: public WThreadedRunner,
public boost::enable_shared_from_this< WBatchLoader >
{
public:
/**
* Initializes the batchloader but does not start it. Use run().
*
* \param fileNames the files to load.
*/
WBatchLoader( std::vector< std::string > fileNames, boost::shared_ptr< WModuleContainer > targetContainer );
/**
* Destructor.
*/
virtual ~WBatchLoader();
/**
* Run thread and load the data.
*/
virtual void run();
protected:
/**
* Function that has to be overwritten for execution. It gets executed in a separate thread after run()
* has been called.
*/
virtual void threadMain();
/**
* List of files to load.
*/
std::vector< std::string > m_fileNamesToLoad;
/**
* The container which later will contain the loaded datasets.
*/
boost::shared_ptr< WModuleContainer > m_targetContainer;
private:
};
#endif // WBATCHLOADER_H
......@@ -39,6 +39,7 @@
#include "WModule.h"
#include "WModuleFactory.h"
#include "WBatchLoader.h"
#include "../common/WException.h"
#include "../common/WCondition.h"
#include "../common/WConditionOneShot.h"
......@@ -147,10 +148,10 @@ void WKernel::threadMain()
{
bool ignore;
m_moduleContainer->add( m_moduleFactory->create( m_moduleFactory->getPrototypeByName( "Navigation Slice Module" ) ) , true );
m_moduleContainer->add( m_moduleFactory->create( m_moduleFactory->getPrototypeByName( "Coordinate System Module" ) ) , true );
//m_moduleContainer->add( m_moduleFactory->create( m_moduleFactory->getPrototypeByName( "Coordinate System Module" ) ) , true );
if( !( WPreferences::getPreference( "modules.standard.ignoreHUD", &ignore ) && ignore ) )
{
m_moduleContainer->add( m_moduleFactory->create( m_moduleFactory->getPrototypeByName( "HUD" ) ) , true );
// m_moduleContainer->add( m_moduleFactory->create( m_moduleFactory->getPrototypeByName( "HUD" ) ) , true );
}
}
......@@ -252,16 +253,12 @@ const WBoolFlag& WKernel::isFinishRequested() const
void WKernel::loadDataSets( std::vector< std::string > fileNames )
{
// add a new data module for each file to load
using boost::shared_ptr;
for( std::vector< std::string >::iterator iter = fileNames.begin(); iter != fileNames.end(); ++iter )
{
shared_ptr< WModule > mod = m_moduleFactory->create( m_moduleFactory->getPrototypeByName( "Data Module" ) );
mod->getProperties()->setValue( "filename" , ( *iter ) );
m_moduleContainer->add( mod );
// serialize loading of a couple of data sets
mod->isReady().wait();
}
getRootContainer()->loadDataSets( fileNames );
}
void WKernel::loadDataSetsSynchronously( std::vector< std::string > fileNames )
{
getRootContainer()->loadDataSetsSynchronously( fileNames );
}
boost::shared_ptr< WModule > WKernel::applyModule( boost::shared_ptr< WModule > applyOn, boost::shared_ptr< WModule > prototype )
......
......@@ -34,6 +34,7 @@
#include "WModule.h"
#include "WModuleFactory.h"
#include "WModuleContainer.h"
#include "WBatchLoader.h"
#include "../common/WLogger.h"
#include "../common/WThreadedRunner.h"
#include "../common/WFlag.h"
......@@ -98,13 +99,21 @@ public:
const WBoolFlag& isFinishRequested() const;
/**
* Load specified datasets.
* Load specified datasets. It immediately returns and starts another thread, which actually loads the data.
*
* \param fileNames list of filenames to load. The registered notification handler for the root container will get notified on
* error and success.
*/
void loadDataSets( std::vector< std::string > fileNames );
/**
* Loads the specified files synchronously.
*
* \param fileNames list of filenames to load. The registered notification handler for the root container will get notified on
* error and success.
*/
void loadDataSetsSynchronously( std::vector< std::string > fileNames );
/**
* Function combines to modules. This is a simple alias for "getRootContainer()->applyModule".
*
......
......@@ -32,10 +32,12 @@
#include "exceptions/WModuleAlreadyAssociated.h"
#include "exceptions/WModuleSignalSubscriptionFailed.h"
#include "../common/WLogger.h"
#include "../common/WThreadedRunner.h"
#include "WKernel.h"
#include "WModuleFactory.h"
#include "WModuleInputConnector.h"
#include "WModuleOutputConnector.h"
#include "WBatchLoader.h"
#include "WModuleContainer.h"
......@@ -142,10 +144,20 @@ void WModuleContainer::remove( boost::shared_ptr< WModule > module )
void WModuleContainer::stop()
{
WLogger::getLogger()->addLogMessage( "Stopping pending threads." , "ModuleContainer (" + m_name + ")", LL_INFO );
// read lock
boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_pendingThreadsLock );
for( std::set< boost::shared_ptr< WThreadedRunner > >::iterator listIter = m_pendingThreads.begin(); listIter != m_pendingThreads.end(); ++listIter )
{
( *listIter )->wait( true );
}
slock.unlock();
WLogger::getLogger()->addLogMessage( "Stopping modules." , "ModuleContainer (" + m_name + ")", LL_INFO );
// read lock
boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_moduleSetLock );
slock = boost::shared_lock<boost::shared_mutex>( m_moduleSetLock );
for( std::set< boost::shared_ptr< WModule > >::iterator listIter = m_modules.begin(); listIter != m_modules.end(); ++listIter )
{
WLogger::getLogger()->addLogMessage( "Waiting for module \"" + ( *listIter )->getName() + "\" to finish." ,
......@@ -243,3 +255,33 @@ boost::shared_ptr< WModule > WModuleContainer::applyModule( boost::shared_ptr< W
return m;
}
boost::shared_ptr< WBatchLoader > WModuleContainer::loadDataSets( std::vector< std::string > fileNames )
{
// create thread which actually loads the data
boost::shared_ptr< WBatchLoader > t = boost::shared_ptr< WBatchLoader >( new WBatchLoader( fileNames, shared_from_this() ) );
t->run();
return t;
}
void WModuleContainer::loadDataSetsSynchronously( std::vector< std::string > fileNames )
{
// create thread which actually loads the data
boost::shared_ptr< WBatchLoader > t = boost::shared_ptr< WBatchLoader >( new WBatchLoader( fileNames, shared_from_this() ) );
t->run();
t->wait();
}
void WModuleContainer::addPendingThread( boost::shared_ptr< WThreadedRunner > thread )
{
boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_pendingThreadsLock );
m_pendingThreads.insert( thread );
lock.unlock();
}
void WModuleContainer::finishedPendingThread( boost::shared_ptr< WThreadedRunner > thread )
{
boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_pendingThreadsLock );
m_pendingThreads.erase( thread );
lock.unlock();
}
......@@ -32,6 +32,10 @@
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include "WModuleSignals.h"
class WThreadedRunner;
class WBatchLoader;
class WModule;
/**
......@@ -128,6 +132,40 @@ public:
*/
virtual boost::shared_ptr< WModule > applyModule( boost::shared_ptr< WModule > applyOn, boost::shared_ptr< WModule > prototype );
/**
* Load specified datasets. It immediately returns and starts another thread, which actually loads the data.
*
* \param fileNames list of filenames to load. The registered notification handler for the root container will get notified on
* error and success.
*/
boost::shared_ptr< WBatchLoader > loadDataSets( std::vector< std::string > fileNames );
/**
* Loads the specified files synchronously.
*
* \param fileNames list of filenames to load. The registered notification handler for the root container will get notified on
* error and success.
*/
void loadDataSetsSynchronously( std::vector< std::string > fileNames );
/**
* Add the specified thread to the list of pending jobs. Only this ensures, that ALL pending threads got stopped before the
* container gets stopped.
*
* \note use this to register threads whenever you start threads belonging to this container. This avoids shutting down the
* container while other threads depend upon them.
*
* \param thread the thread to add
*/
void addPendingThread( boost::shared_ptr< WThreadedRunner > thread );
/**
* The specified thread has finished and does not longer depend upon this container instance.
*
* \param thread the thread.
*/
void finishedPendingThread( boost::shared_ptr< WThreadedRunner > thread );
protected:
/**
......@@ -180,6 +218,16 @@ protected:
*/
std::list< t_ModuleGenericSignalHandlerType > m_associatedNotifiers;
/**
* Set of all threads that currently depend upon this container.
*/
std::set< boost::shared_ptr< WThreadedRunner > > m_pendingThreads;
/**
* Lock for m_pendingThreads.
*/
boost::shared_mutex m_pendingThreadsLock;
private:
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment