From c12dbe29080d78f56b17300532c9aa27ed83edab Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Wed, 3 May 2000 13:23:46 +0000 Subject: [PATCH] Add the SwappableVector from the wave program. git-svn-id: https://svn.dealii.org/trunk@2787 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/lac/include/lac/swappable_vector.h | 283 ++++++++++++++++++ .../include/lac/swappable_vector.templates.h | 260 ++++++++++++++++ deal.II/lac/source/swappable_vector.cc | 19 ++ 3 files changed, 562 insertions(+) create mode 100644 deal.II/lac/include/lac/swappable_vector.h create mode 100644 deal.II/lac/include/lac/swappable_vector.templates.h create mode 100644 deal.II/lac/source/swappable_vector.cc diff --git a/deal.II/lac/include/lac/swappable_vector.h b/deal.II/lac/include/lac/swappable_vector.h new file mode 100644 index 0000000000..af2e7a348f --- /dev/null +++ b/deal.II/lac/include/lac/swappable_vector.h @@ -0,0 +1,283 @@ +//---------------------------- swappable_vector.h --------------------------- +// $Id$ +// Version: $Name$ +// +// Copyright (C) 1999, 2000 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//---------------------------- swappable_vector.h --------------------------- +#ifndef __deal2__swappable_vector_h +#define __deal2__swappable_vector_h + + +#include + +#ifdef DEAL_II_USE_MT +# include +#endif + +#include + + + +/** + * This class is a wrapper to the #Vector# class which allows to swap + * out the data to a file and reload it later on. It handles the + * management of the name of the file where the data is to be stored + * temporarily and removes the file is necessary at the end of the + * lifetime of the vector. + * + * There are functions to swap the data to a file, and to reload + * it. There is also a function #alert# that can be used to signal to + * an object of this class that the data will be needed shortly, so + * the object can initiate that the data be loaded already. While in + * non-multithreading mode, this function has no effect since #reload# + * has to be called afterwards anyway. On the other hand, in + * multithreading mode, the data is preloaded in the background using + * a thread on its own, and may already be available at the time when + * #reload# is called. If it is not available, #reload# waits until + * the detached thread has loaded the data. + * + * @author Wolfgang Bangerth, 1999, 2000 + */ +template +class SwappableVector : public Vector +{ + public: + /** + * Constructor. Does nothing + * apart from calling the + * constructor of the underlying + * class. + */ + SwappableVector (); + + /** + * Copy constructor. Copies the + * data if #v# contains some, but + * does not do so if #v# is empty + * or has its data swapped + * out. In the latter case, warn + * about that. In particular do + * not take over ownership of any + * files that #v# might own (as, + * for example, #C++#'s + * #auto_ptr# objects would do). + */ + SwappableVector (const SwappableVector &v); + + /** + * Destructor. If this class + * still owns a file to which + * temporary data was stored, + * then it is deleted. + */ + virtual ~SwappableVector (); + + /** + * Copy operator. Do mostly the + * same as the copy constructor + * does; if necessary, delete + * temporary files owned by this + * object at first. + */ + SwappableVector & operator = (const SwappableVector &); + + /** + * Swap out the data of this + * vector to the file of which + * the name is given. It is + * assumed that the file can be + * overwritten if it exists, and + * ownership of this file is + * assumed by this object. The + * file is deleted either upon + * calling #kill_file#, or on + * destruction of this object. + * + * The content of the vector is + * cleared and it size is reset + * to zero. + * + * If this object owns another + * file, for example when + * #swap_out# but no #kill_file# + * has previously been called, + * then that is deleted first. + */ + void swap_out (const string &filename); + + /** + * Reload the data of this vector + * from the file to which it has + * been stored previously using + * #swap_out#. Since the file is + * not deleted after reloading, + * you can call #reload# multiple + * times, in between you may do + * everything with the vector, + * including changing its size. + * + * This function resets the size + * of the vector to the number of + * elements there were upon + * calling #swap_out# before. + */ + void reload (); + + /** + * Calling this function can be + * used to alert this vector that + * it will need to reload its + * data soon. It has no effect if + * the data of the vector is + * already present, and it has no + * effect in single-thread mode + * as well, but in multithread + * mode, it spawns another thread + * that reads the data in + * parallel to the usual + * execution of the program, such + * that when #reload# is called, + * the data may eventually be + * available already. It might + * therefore be wirthwhile to + * call this function some time + * in advance, if you know that + * the data will be needed, and + * loading takes some time, for + * instance if the file to which + * the data was written is not in + * a local tmp directory. + * + * Calling this function multiple + * times before calling #reload# + * is allowed and has no effect + * for subsequent calls. Calling + * this function while the data + * is still or already in memory + * is allowed and has no effect. + */ + void alert (); + + + /** + * Remove the file to which the + * data has been stored the last + * time. After this, the object + * does not own any file any + * more, so of course you can't + * call #reload# no more. + * + * If this object does not own a + * file, for example since + * #swap_out# was not called, or + * because #kill_file# has been + * called previously, then this + * function does nothing. + */ + void kill_file (); + + /** + * Return the name of the file to + * which the data was stored the + * last time you called + * #swap_out#. If #swap_out# was + * not called, or if in between + * #kill_file# was called, then + * the filename is an empty + * string. + */ + const string & get_filename () const; + + /** + * Exception. + */ + DeclException0 (ExcSizeZero); + /** + * Exception. + */ + DeclException0 (ExcSizeNonzero); + /** + * Exception. + */ + DeclException1 (ExcInvalidFilename, + string, + << "The filename <" << arg1 + << "> is not a valid one here."); + /** + * Exception. + */ + DeclException0 (ExcInvalidCopyOperation); + + private: + /** + * Name of the file to which data + * was swapped out. If no data is + * presently swapped out + * (i.e. before calling + * #swap_out# and after + * #kill_file#), the string is + * empty, indicating no ownership + * of files. + */ + string filename; + +#ifdef DEAL_II_USE_MT + /** + * If in multithread mode, then + * the #alert# function has + * functionality, but needs to + * coordinate with the #reload# + * function. This is done through + * the following lock. + */ + ACE_Thread_Mutex lock; + + /** + * Declare a thread manager that + * is used to spawn threads in + * #alert# detached. + */ + static ACE_Thread_Manager thread_manager; +#endif + + /** + * Flag by which the #alert# + * function signifies that the + * data has been preloaded + * already. This flag is always + * #false# in non-MT mode. + */ + bool data_is_preloaded; + + /** + * Internal function that + * actually reloads the + * vector. Called from #reload# + * and #alert#. + * + * The parameter specifies + * whether the function shall set + * #data_is_preloaded# or + * not. The calling functions + * can't sometimes do this + * themselves, since they call + * this function detached, so + * this function has to signal + * success itself if this is + * required. + */ + void reload_vector (const bool set_flag); +}; + + + +/*---------------------------- swappable_vector.h ---------------------------*/ +/* end of #ifndef __deal2__swappable_vector_h */ +#endif +/*---------------------------- swappable_vector.h ---------------------------*/ diff --git a/deal.II/lac/include/lac/swappable_vector.templates.h b/deal.II/lac/include/lac/swappable_vector.templates.h new file mode 100644 index 0000000000..6f825bb2f0 --- /dev/null +++ b/deal.II/lac/include/lac/swappable_vector.templates.h @@ -0,0 +1,260 @@ +//---------------------------- swappable_vector.templates.h --------------------------- +// $Id$ +// Version: $Name$ +// +// Copyright (C) 1999, 2000 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//---------------------------- swappable_vector.templates.h --------------------------- +#ifndef __deal2__swappable_vector_templates_h +#define __deal2__swappable_vector_templates_h + + +#include +#include +#include + + + +#ifdef DEAL_II_USE_MT + // allocate static variable +template +ACE_Thread_Manager SwappableVector::thread_manager; +#endif + + + + +template +SwappableVector::SwappableVector () + : + data_is_preloaded (false) +{}; + + + +template +SwappableVector::SwappableVector (const SwappableVector &v) : + Vector(v), + filename (), + data_is_preloaded (false) +{ + Assert (v.filename == "", ExcInvalidCopyOperation()); +}; + + + +template +SwappableVector::~SwappableVector () +{ + // if the vector was stored in a + // file previously, and that has + // not been deleted in the + // meantime, then we kill that file + // first, before killing the vector + // itself + + if (filename != "") + kill_file (); +}; + + + +template +SwappableVector & +SwappableVector::operator= (const SwappableVector &v) +{ + // if necessary, first delete data + if (filename != "") + kill_file (); + + // if in MT mode, block all other + // operations +#ifdef DEAL_II_USE_MT + lock.acquire (); +#endif + + Vector::operator = (v); + data_is_preloaded = false; + +#ifdef DEAL_II_USE_MT + lock.release (); +#endif + + + return *this; +}; + + + +template +void SwappableVector::swap_out (const string &name) +{ + // if the vector was stored in + // another file previously, and + // that has not been deleted in the + // meantime, then we kill that file + // first + if (filename != "") + kill_file (); + + filename = name; + + Assert (size() != 0, ExcSizeZero()); + + // if in MT mode, block all other + // operations +#ifdef DEAL_II_USE_MT + lock.acquire (); +#endif + + // check that we have not called + // #alert# without the respective + // #reload# function + Assert (data_is_preloaded == false, ExcInternalError()); + + ofstream tmp_out(filename.c_str()); + block_write (tmp_out); + tmp_out.close (); + + reinit (0); + +#ifdef DEAL_II_USE_MT + lock.release (); +#endif +}; + + + +template +void SwappableVector::reload () +{ + // if in MT mode: synchronise with + // possibly existing #alert# calls +#ifdef DEAL_II_USE_MT + lock.acquire (); +#endif + // if data was already preloaded, + // then there is no more need to + // load it + if (data_is_preloaded == false) + // reload data. note that this + // function also releases the + // lock + reload_vector (false); + else + { + // clear flag since no more + // needed + data_is_preloaded = false; + + // release lock. the lock is + // also released in the other + // branch of the if-clause +#ifdef DEAL_II_USE_MT + lock.release (); +#endif + }; +}; + + + +template +void SwappableVector::alert () +{ + // note: this function does nothing + // in non-MT mode +#ifdef DEAL_II_USE_MT + + // synchronise with possible other + // invokations of this function and + // other functions in this class + lock.acquire (); + + // calling this function multiple + // times does no harm: + if ( (data_is_preloaded == true) || + // calling this function while the + // vector is active does no harm + // either + (size() != 0)) + lock.release (); + else + // data has not been preloaded so + // far, so go on! + Threads::spawn (thread_manager, + Threads::encapsulate (&SwappableVector::reload_vector) + .collect_args(this, true)); + // note that reload_vector also + // releases the lock +#endif +}; + + + +template +void SwappableVector::reload_vector (const bool set_flag) +{ + Assert (filename != "", ExcInvalidFilename (filename)); + Assert (size() == 0, ExcSizeNonzero()); + + ifstream tmp_in(filename.c_str()); + block_read (tmp_in); + tmp_in.close (); + + // release the lock that was + // acquired by the calling + // functions +#ifdef DEAL_II_USE_MT + // set the flag if so required + if (set_flag) + data_is_preloaded = true; + lock.release (); +#endif +}; + + + +template +void SwappableVector::kill_file () +{ + // if in MT mode, wait for other + // operations to finish first + // (there should be none, but who + // knows) +#ifdef DEAL_II_USE_MT + lock.acquire(); +#endif + + Assert (data_is_preloaded == false, ExcInternalError()); + + if (filename != "") + { + int status = remove (filename.c_str()); + AssertThrow (status == 0, ExcInternalError()); + + filename = ""; + }; + +#ifdef DEAL_II_USE_MT + lock.release (); +#endif +}; + + + +template +const string & +SwappableVector::get_filename () const +{ + return filename; +}; + + + + +#endif // __deal2__swappable_vector_templates_h diff --git a/deal.II/lac/source/swappable_vector.cc b/deal.II/lac/source/swappable_vector.cc new file mode 100644 index 0000000000..cf197881b0 --- /dev/null +++ b/deal.II/lac/source/swappable_vector.cc @@ -0,0 +1,19 @@ +//---------------------------- swappable_vector.cc --------------------------- +// $Id$ +// Version: $Name$ +// +// Copyright (C) 1999, 2000 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//---------------------------- swappable_vector.cc --------------------------- + + +#include + +// explicit instantiations +template class SwappableVector; +template class SwappableVector; -- 2.39.5