Commit 9db50232 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE] - project files now get loaded asynchronoulsy to avoid a stuck GUI...

[CHANGE] - project files now get loaded asynchronoulsy to avoid a stuck GUI for large datasets (like fiber datasets)
parent df06f703
......@@ -171,8 +171,11 @@ int WQt4Gui::run()
{
try
{
WModuleProjectFileCombiner proj = WModuleProjectFileCombiner( m_optionsMap["project"].as< std::string >() );
proj.apply();
boost::shared_ptr< WModuleProjectFileCombiner > proj = boost::shared_ptr< WModuleProjectFileCombiner >(
new WModuleProjectFileCombiner( m_optionsMap["project"].as< std::string >() )
);
// This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
proj->run();
}
catch( const WException& e )
{
......
......@@ -22,12 +22,15 @@
//
//---------------------------------------------------------------------------
#include "../common/WLogger.h"
#include "WKernel.h"
#include "WModuleContainer.h"
#include "WModuleCombiner.h"
WModuleCombiner::WModuleCombiner( boost::shared_ptr< WModuleContainer > target ):
WThreadedRunner(),
m_container( target )
{
// initialize members
......@@ -44,3 +47,27 @@ WModuleCombiner::~WModuleCombiner()
// cleanup
}
void WModuleCombiner::run()
{
// the module needs to be added here, as it else could be freed before the thread finishes ( remember: it is a shared_ptr).
m_container->addPendingThread( shared_from_this() );
// actually run
WThreadedRunner::run();
}
void WModuleCombiner::threadMain()
{
try
{
apply();
}
catch( ... )
{
wlog::error( "ModuleCombiner" ) << "Exception thrown. Aborting module combiner.";
}
// remove from list of threads
m_container->finishedPendingThread( shared_from_this() );
}
......@@ -25,6 +25,10 @@
#ifndef WMODULECOMBINER_H
#define WMODULECOMBINER_H
#include <boost/shared_ptr.hpp>
#include "../common/WThreadedRunner.h"
#include "WModuleContainer.h"
/**
......@@ -34,7 +38,8 @@
* loads projects files and creates a module graph out of it. The only think which all the combiners need to know: the target container. Derive
* all specific combiner classes from this one.
*/
class WModuleCombiner
class WModuleCombiner: public WThreadedRunner,
public boost::enable_shared_from_this< WModuleCombiner >
{
public:
......@@ -59,11 +64,23 @@ public:
* Apply the internal module structure to the target container. Be aware, that this operation might take some time, as modules can be
* connected only if they are "ready", which, at least with WMData modules, might take some time.
*
* \note: to have asynchronous loading, use run().
*/
virtual void apply() = 0;
/**
* Run thread and call apply(). This is useful to apply a combiner asynchronously.
*/
virtual void run();
protected:
/**
* Function that has to be overwritten for execution. It gets executed in a separate thread after run()
* has been called. It actually calls apply() in another thread.
*/
virtual void threadMain();
/**
* The module container to use for the modules.
*/
......
......@@ -49,14 +49,14 @@ WModuleProjectFileCombiner::WModuleProjectFileCombiner( boost::filesystem::path
WModuleCombiner( target ),
m_project( project )
{
// initialize members
parse();
}
WModuleProjectFileCombiner::WModuleProjectFileCombiner( boost::filesystem::path project ):
WModuleCombiner( WKernel::getRunningKernel()->getRootContainer() ),
m_project( project )
{
// initialize members
parse();
}
WModuleProjectFileCombiner::~WModuleProjectFileCombiner()
......@@ -64,8 +64,9 @@ WModuleProjectFileCombiner::~WModuleProjectFileCombiner()
// cleanup
}
void WModuleProjectFileCombiner::apply()
void WModuleProjectFileCombiner::parse()
{
// Parse the file
wlog::info( "Kernel" ) << "Loading project file \"" << m_project.file_string() << "\".";
// read the file
......@@ -81,21 +82,6 @@ void WModuleProjectFileCombiner::apply()
static const boost::regex propRe( "^PROPERTY:\\(([0-9]*),(.*)\\)=(.*)$" );
static const boost::regex commentRe( "^//.*$" );
// some maps which describe the module graph
// These maps are used to read in the file and to later on build the actual graph
typedef std::pair< unsigned int, boost::shared_ptr< WModule > > ModuleID;
std::map< unsigned int, boost::shared_ptr< WModule > > modules;
// list of connections
typedef std::pair< unsigned int, std::string > Connector;
typedef std::pair< Connector, Connector > Connection;
std::list< Connection > connections;
// list of properties
typedef std::pair< unsigned int, std::string > Property;
typedef std::pair< Property, std::string > PropertyValue;
std::list< PropertyValue > properties;
// read it line by line
std::string line; // the current line
boost::smatch matches; // the list of matches
......@@ -121,7 +107,7 @@ void WModuleProjectFileCombiner::apply()
else
{
boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto );
modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) );
m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) );
}
}
else if ( boost::regex_match( line, matches, conRe ) )
......@@ -134,7 +120,7 @@ void WModuleProjectFileCombiner::apply()
" and \"" << matches[4] << "\" of module " << matches[3] << ".";
// now we search in modules[ matches[1] ] for an output connector named matches[2]
connections.push_back( Connection( Connector( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ),
m_connections.push_back( Connection( Connector( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ),
Connector( boost::lexical_cast< unsigned int >( matches[3] ), matches[4] ) ) );
}
else if ( boost::regex_match( line, matches, propRe ) )
......@@ -147,7 +133,7 @@ void WModuleProjectFileCombiner::apply()
wlog::debug( "Project Loader [Parser]" ) << "Line " << i << ": Property \"" << matches[2] << "\" of module " << matches[1] << " set to "
<< matches[3];
properties.push_back( PropertyValue( Property( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ), matches[3] ) );
m_properties.push_back( PropertyValue( Property( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ), matches[3] ) );
}
else if ( !line.empty() && !boost::regex_match( line, matches, commentRe ) )
{
......@@ -156,18 +142,21 @@ void WModuleProjectFileCombiner::apply()
}
// close it
input.close();
}
void WModuleProjectFileCombiner::apply()
{
// now, as we have created the modules, we need to set the properties for each of it.
for ( std::list< PropertyValue >::const_iterator iter = properties.begin(); iter != properties.end(); ++iter )
for ( std::list< PropertyValue >::const_iterator iter = m_properties.begin(); iter != m_properties.end(); ++iter )
{
// grab corresponding module
if ( !modules.count( ( *iter ).first.first ) )
if ( !m_modules.count( ( *iter ).first.first ) )
{
wlog::error( "Project Loader" ) << "There is no module with ID \"" << ( *iter ).first.first << "\" to set the property \"" <<
( *iter ).first.second << "\" for. Skipping.";
continue;
}
boost::shared_ptr< WModule > m = modules[ ( *iter ).first.first ];
boost::shared_ptr< WModule > m = m_modules[ ( *iter ).first.first ];
// has this module the specified property?
boost::shared_ptr< WPropertyBase > prop = m->getProperties2()->findProperty( ( *iter ).first.second );
......@@ -185,14 +174,14 @@ void WModuleProjectFileCombiner::apply()
}
// now add each module to the target container
for ( std::map< unsigned int, boost::shared_ptr< WModule > >::const_iterator iter = modules.begin(); iter != modules.end(); ++iter )
for ( std::map< unsigned int, boost::shared_ptr< WModule > >::const_iterator iter = m_modules.begin(); iter != m_modules.end(); ++iter )
{
m_container->add( ( *iter ).second );
}
// now wait for the modules to get ready. We could have waited for this in the previous loop, but a long loading module would block others.
// -> so we wait after adding and starting them
for ( std::map< unsigned int, boost::shared_ptr< WModule > >::iterator iter = modules.begin(); iter != modules.end(); ++iter )
for ( std::map< unsigned int, boost::shared_ptr< WModule > >::iterator iter = m_modules.begin(); iter != m_modules.end(); ++iter )
{
( *iter ).second->isReadyOrCrashed().wait();
......@@ -201,12 +190,12 @@ void WModuleProjectFileCombiner::apply()
{
wlog::warn( "Project Loader" ) << "The module with ID " << ( *iter ).first << " crashed. Connections and properties relating to this"
<< " module will fail.";
modules.erase( iter );
m_modules.erase( iter );
}
}
// and finally, connect them all together
for ( std::list< Connection >::const_iterator iter = connections.begin(); iter != connections.end(); ++iter )
for ( std::list< Connection >::const_iterator iter = m_connections.begin(); iter != m_connections.end(); ++iter )
{
// each connection contains two connectors
Connector c1 = ( *iter ).first;
......@@ -215,24 +204,24 @@ void WModuleProjectFileCombiner::apply()
// each of these connectors contains the module ID and the connector name
// grab corresponding module 1
boost::shared_ptr< WModule > m1;
if ( !modules.count( c1.first ) )
if ( !m_modules.count( c1.first ) )
{
wlog::error( "Project Loader" ) << "There is no module with ID \"" << c1.first << "\" for the connection "
<< "(" << c1.first << "," << c1.second << ")->(" << c2.first << "," << c2.second << "). Skipping.";
continue;
}
m1 = modules[ c1.first ];
m1 = m_modules[ c1.first ];
boost::shared_ptr< WModule > m2;
if ( !modules.count( c2.first ) )
if ( !m_modules.count( c2.first ) )
{
wlog::error( "Project Loader" ) << "There is no module with ID \"" << c2.first << "\" for the connection "
<< "(" << c1.first << "," << c1.second << ")->(" << c2.first << "," << c2.second << "). Skipping.";
continue;
}
m2 = modules[ c2.first ];
m2 = m_modules[ c2.first ];
// now we have the modules referenced by the ID
// -> query the connectors
......@@ -272,8 +261,8 @@ void WModuleProjectFileCombiner::apply()
}
// clear all our lists (deref all contained pointers)
modules.clear();
connections.clear();
properties.clear();
m_modules.clear();
m_connections.clear();
m_properties.clear();
}
......@@ -25,6 +25,11 @@
#ifndef WMODULEPROJECTFILECOMBINER_H
#define WMODULEPROJECTFILECOMBINER_H
#include <list>
#include <map>
#include <string>
#include <utility>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
......@@ -79,6 +84,51 @@ protected:
*/
boost::filesystem::path m_project;
/**
* The module ID type. A pair of ID and pointer to module.
*/
typedef std::pair< unsigned int, boost::shared_ptr< WModule > > ModuleID;
/**
* All Modules.
*/
std::map< unsigned int, boost::shared_ptr< WModule > > m_modules;
/**
* A connector is described by ID and name.
*/
typedef std::pair< unsigned int, std::string > Connector;
/**
* A connection is a pair of connectors.
*/
typedef std::pair< Connector, Connector > Connection;
/**
* All connections.
*/
std::list< Connection > m_connections;
/**
* A property is a pair of ID and name.
*/
typedef std::pair< unsigned int, std::string > Property;
/**
* A property value is a property and the new value as string.
*/
typedef std::pair< Property, std::string > PropertyValue;
/**
* All properties.
*/
std::list< PropertyValue > m_properties;
/**
* Parses the input file and fills m_modules, m_connections and m_properites.
*/
void parse();
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