| <<O>> Difference Topic MigratingToVrjTwoTwo (r1.4 - 15 Nov 2006 - PatrickHartling) |
Porting from VR Juggler 2.0 to 2.2 | ||||||||
| Line: 37 to 37 | ||||||||
|---|---|---|---|---|---|---|---|---|
| The exceptions thrown by I/O methods are the following (indentation indicates class hierarchy): | ||||||||
| Changed: | ||||||||
| < < |
| |||||||
| > > |
| |||||||
Application-Specific Cluster Data | ||||||||
| Line: 247 to 247 | ||||||||
#include <vpr/vprParam.h> #include <vpr/Thread/Thread.h> | ||||||||
| Added: | ||||||||
| > > |
#if __VPR_version >= 1001016
# include | |||||||
| class MyClass? { | ||||||||
| Line: 350 to 353 | ||||||||
Synchronization Primitives | ||||||||
| Added: | ||||||||
| > > |
The syntactic and semantic behavior of the VPR synchronization primitives have changed to eliminate the use of vpr::ReturnStatus in favor of using exceptions. Now, locking and unlocking operations are guaranteed to succeed as long as the synchronization primitive object was constructed successfully. All the classes in VPR related to thread synchronization throw exceptions derived from vpr::Exception instead of using vpr::ReturnStatus. Every method that throws an exception is documented to identify which exceptions are thrown and under what circumstances a given exception will be thrown. The synchronization classes that have been affected by this change are as follows:
vpr::Mutex::acquire() and vpr::Mutex::release() returned a vpr::ReturnStatus to indicate whether the lock/unlock operation succeeded. Now, these methods have a void return type. If locking/unlocking should fail due to an exceptional case, then an exception is thrown.
These changes were made in the following VPR versions:
__VPR_version against either 1001033 (the encoding of 1.1.33) or 2000000 (the encoding of 2.0.0). Since most of these version increments were made in quick succession, it is highly unlikely that code would need to work with all the different VPR 1.1 versions.
Synchronization ExceptionsThe exceptions thrown by synchronization methods are the following (indentation indicates class hierarchy):
vpr::ResourceException is thrown by the constructor of each of the various synchronization classes if allocation of the platform-specific synchronization primitive should fail. In that case, there is no way for the VPR synchronization object to be used, and all locking and unlocking methods would fail.
The exception type vpr::LockException is thrown if a lock or unlock operation fails due to misuse of the object. For example, if vpr::Mutex::release() is invoked on an object from a thread that is not currently holding the mutex lock, then that is a misuse of the mutex object, and vpr::LockException is thrown. Similarly, if vpr::CondVar::signal() or vpr::CondVar::broadcast() is invoked on a condition variable object that is not currently locked, that violates the contract of those methods, and vpr::LockException is thrown.
The exception type vpr::DeadlockException is thrown when an attempt to lock a synchronization object would cause a thread to deadlock. This occurs when the same thread tries to lock the same mutex twice. The operating system detects this case and reports it, and VPR synchronization objects translate this error code into a vpr::DeadlockException that is thrown. Previously, this case was only "reported" through an assertion failure when building with _DEBUG defined, so this change is definitely a big improvement.
Return Type ChangesThe synchronization classes all have a non-blocking lock acquisition method namedtryAcquire(), and many have tryAcquireRead() and tryAcquireWrite() methods. In VPR 1.0, these methods return a vpr::ReturnStatus object to indicate whether or not the lock was acquired. Since this operation either succeeded in acquiring the lock or failing to do so, the return type was changed to bool to allow simplification of user-level code. The following example shows a simple use of vpr::Guard<vpr::Mutex> and vpr::Mutex::tryAcquire() that will compile with VPR 1.0, 1.1, and 2.0:
#include <boost/noncopyable.hpp>
#include <vpr/vprParam.h>
#include <vpr/Sync/Mutex.h>
#include <vpr/Sync/Guard.h>
// The class is non-copyable because vpr::Mutex is non-copayble.
class MyClass : boost::noncopyable
{
public:
void changeData(const int newValue)
{
// Acquires the mutex on construction; releases it on destruction.
vpr::Guard<vpr::Mutex> g(mMutex);
mData = newValue;
}
bool useData()
{
#if __VPR_version < 1001033
const bool locked = mMutex.tryAcquire().success();
#else
const bool locked = mMutex.tryAcquire();
#endif
int result(-1);
if ( locked )
{
const int cur_value(mData);
mMutex.release();
// Do work based on cur_value ...
}
return locked;
}
private:
vpr::Mutex mMutex;
int mData;
};
We could take the above example a little farther by handling the case of deadlock detection in the implementation of MyClass::changeData(), as shown below (note that vpr/Sync/DeadlockException.h would need to be included):
void changeData(const int newValue)
{
#if __VPR_version >= 1001033
try
{
// Acquires the mutex on construction; releases it on destruction.
// If an exception is thrown during mutex acquisition, g is
// automatically destroyed, but no change is made to the state of
// mMutex.
vpr::Guard<vpr::Mutex> g(mMutex);
mData = newValue;
}
// If deadlock was detected, then this thread is already holding a
// lock on mMutex, so it is still save to change mData.
catch (vpr::DeadlockException& ex)
{
mData = newValue;
}
#else
// Acquires the mutex on construction; releases it on destruction.
vpr::Guard<vpr::Mutex> g(mMutex);
mData = newValue;
#endif
}
This example is rather contrived and is intended to demonstrate what options exist for handling deadlock detection and how vpr::Guard<vpr::Mutex> will behave in this context.
| |||||||
Using Flagpoll | ||||||||
| <<O>> Difference Topic MigratingToVrjTwoTwo (r1.3 - 29 Oct 2006 - PatrickHartling) |
Porting from VR Juggler 2.0 to 2.2 | ||||||||
| Line: 8 to 8 | ||||||||
|---|---|---|---|---|---|---|---|---|
The VR Juggler Portable Runtime (VPR) has undergone extensive work to improve error reporting through the use of exceptions (derived from vpr::Exception) rather than the clumsier use of vpr::ReturnStatus. Methods in VPR 1.0 classes that used to return vpr::ReturnStatus (generally) now have a void return type and report errors by throwing exceptions. In some cases, the use of vpr::ReturnStatus as the return type was replaced by returning a bool and throwing exceptions to report critical errors. This was only done for cases where an operation can "fail" under standard usage; exceptions are used to report exceptional cases.
| ||||||||
| Added: | ||||||||
| > > |
Ultimately, VPR 2.0 does not use vpr::ReturnStatus, and the class is basically considered deprecated. It is not scheduled to be removed, but as VR Juggler 2.x evolves, the internal use of vpr::ReturnStatus will eventually be eliminated. While the API changes may be unpleasant to deal with, the end result will be worth it. Exceptions allow for much cleaner algorithm implementations because the error handling can usually be separated from the algorithm. Code flow within a try/catch block is almost always easier to follow and understand as a result. Furthermore, exceptions are a much more expressive and scalable way of reporting errors than error codes.
| |||||||
In general, most VR Juggler applications will probably not be affected by the VPR 2.0 API changes. Those that use sockets or create and manage threads will have to be updated, though. The most likely place where users would be tripped up is by the change in return type for vpr::ReadableObject::readObject() and vpr::WritableObject::writeObject(). In VPR 2.0, these methods have a void return type, and user implementations must throw exceptions of type vpr::IOException (or a subclass thereof) to indicate errors in object serialization and object de-serialization. See below for more information.
I/O Classes | ||||||||
| Added: | ||||||||
| > > |
All the classes in VPR related to input and output throw exceptions derived from vpr::Exception instead of using vpr::ReturnStatus. Every method that throws an exception is documented to identify which exceptions are thrown and under what circumstances a given exception will be thrown. The I/O classes that have been affected by this change are as follows:
I/O ExceptionsThe exceptions thrown by I/O methods are the following (indentation indicates class hierarchy):
| |||||||
Application-Specific Cluster Data | ||||||||
| Changed: | ||||||||
| < < |
The changes to the return type of vpr::ReadableObject::readObject() and vpr::WritableObject::writeObject() impact code written for sharing application-specific data in a cluster. These changes were made as part of VPR 1.1.5, so all code built against versions of VPR prior to this must return vpr::ReturnStatus in their override of these methods. For VPR 1.1.5 and beyond, the return type must be void. The following shows an example of how to write code that will work with VPR 1.0, 1.1, and 2.0. Here, the VPR 1.1.5 version number is encoded as 1001005, and the encoded version can be queried from the __VPR_version preprocessor symbol defined in vpr/vprParam.h.
| |||||||
| > > |
The changes to the return type of vpr::ReadableObject::readObject() and vpr::WritableObject::writeObject() impact code written for sharing application-specific data in a cluster. These changes were made as part of VPR 1.1.5, so all code built against versions of VPR prior to this must return vpr::ReturnStatus in their override of these methods. For VPR 1.1.5 and beyond, the return type must be void. The following shows an example of how to write code that will work with VPR 1.0, 1.1, and 2.0. Here, the VPR 1.1.5 version number is encoded as 1001005, and the encoded version can be queried from the __VPR_version preprocessor symbol defined in vpr/vprParam.h.
| |||||||
#include <vpr/vprParam.h> | ||||||||
| Line: 51 to 88 | ||||||||
| }; | ||||||||
| Added: | ||||||||
| > > |
The methods of vpr::ObjectWriter and vpr::ObjectReader throw exceptions if anything goes wrong while serializing or de-serializing an object. The exception will be of type vpr::IOException or vpr::EOFException (a subclass of vpr::IOException). Code that would be operating on objects of type vpr::ReadableObject or vpr::WritableObject must be written to handle these exceptions when calling vpr::ReadableObject::readObject() and vpr::WritableObject::writeObject(). Thus, implementations of these methods do not need to worry about catching exceptions thrown by vpr::ObjectReader or vpr::ObjectWriter. Of course, there may be a desire to catch these errors during the serialization and/or de-serialization process. In this case, the programmer should re-throw the exception after handling it so that the higher level code knows that something went wrong. An example of this is shown below:
#include <vector>
#include <vpr/IO/ObjectReader.h>
#include <vpr/IO/EOFException.h>
#include <plugins/ApplicationDataManager/UserData.h>
class MyType : public vpr::SerializableObject
{
public:
void readObject(vpr::ObjectReader* reader)
{
try
{
const vpr::Uint8 val_count = reader->readUint8();
std::vector<vpr::Uint32> values(val_count);
for ( vpr::Uint8 i = 0; i < val_count; ++i )
{
values[i] = reader->readUint32();
}
// Wait to replace mValues until we know that we have
// read everything.
mValues = values;
}
catch (vpr::EOFException& ex)
{
std::cerr << "Ran out of data unexpectedly:\n"
<< ex.what() << std::endl;
throw;
}
catch (vpr::IOException& ex)
{
std::cerr << "I/O error occurred during de-serialization:\n"
<< ex.what() << std::endl;
throw;
}
}
// writeObject() implementation omitted
private:
std::vector<vpr::Uint32> mValues;
};
Of course, the exception handling in the above example is not very interesting since it just prints a different error message based on the exception type. One can imagine more complex uses, however, and the point of the above example is to demonstrate what is possible rather than to give a definitive example of what to do in all cases.
Querying Environment VariablesThe helper functionsvpr::System::getenv() and vpr::System::setenv() have had their return type changed from vpr::ReturnStatus to bool. Since these methods either succeed or fail, using vpr::ReturnStatus was overkill. This change was made in VPR 1.1.35 (encoded as 1001035 in the preprocessor symbol __VPR_version as defined in vpr/vprParam.h). The following shows an example of how to use vpr::System::getenv() in a way that will work with VPR 1.0, 1.1, and 2.0:
#include <vpr/vprParam.h>
#include <vpr/System.h>
void f()
{
const std::string envvar("SOME_VAR");
std::string value;
#if __VPR_version < 10010135
const bool result = vpr::System::getenv(envvar, value).success();
#else
const bool result = vpr::System::getenv(envvar, value);
#endif
if ( result )
{
// Do something with value ...
}
}
Another approach that does not require the version testing would be the following:
#include <vpr/System.h>
void f()
{
std::string value;
vpr::System::getenv("SOME_VAR", value);
if ( ! value.empty() )
{
// Do something with value ...
}
}
| |||||||
ThreadsThe use ofvpr::ThreadFunctor has been replaced by the much more powerful and flexible Boost.Function. In VPR 1.0, threads were created using one of the following approaches:
| ||||||||
| Line: 96 to 224 | ||||||||
|
void threadFunc(const int val,
std::vector | ||||||||
| Added: | ||||||||
| > > |
vecRef.reserve(val); | |||||||
| for ( int i = 0; i < val; ++i ) { vecRef.push_back(SomeClass?(i)); | ||||||||
| Line: 106 to 235 | ||||||||
|
{
std::vector | ||||||||
| Changed: | ||||||||
| < < |
new vpr::Thread(boost::bind(threadFunc, val, boost::ref(vec)); | |||||||
| > > |
new vpr::Thread(boost::bind(threadFunc, val, boost::ref(vec)); | |||||||
| thread->join(); std::cout << vec.size() << std::endl; } | ||||||||
| <<O>> Difference Topic MigratingToVrjTwoTwo (r1.2 - 27 Oct 2006 - PatrickHartling) |
Porting from VR Juggler 2.0 to 2.2 | ||||||||
| Line: 8 to 8 | ||||||||
|---|---|---|---|---|---|---|---|---|
The VR Juggler Portable Runtime (VPR) has undergone extensive work to improve error reporting through the use of exceptions (derived from vpr::Exception) rather than the clumsier use of vpr::ReturnStatus. Methods in VPR 1.0 classes that used to return vpr::ReturnStatus (generally) now have a void return type and report errors by throwing exceptions. In some cases, the use of vpr::ReturnStatus as the return type was replaced by returning a bool and throwing exceptions to report critical errors. This was only done for cases where an operation can "fail" under standard usage; exceptions are used to report exceptional cases.
| ||||||||
| Added: | ||||||||
| > > |
In general, most VR Juggler applications will probably not be affected by the VPR 2.0 API changes. Those that use sockets or create and manage threads will have to be updated, though. The most likely place where users would be tripped up is by the change in return type for vpr::ReadableObject::readObject() and vpr::WritableObject::writeObject(). In VPR 2.0, these methods have a void return type, and user implementations must throw exceptions of type vpr::IOException (or a subclass thereof) to indicate errors in object serialization and object de-serialization. See below for more information.
| |||||||
I/O Classes | ||||||||
| Added: | ||||||||
| > > |
Application-Specific Cluster DataThe changes to the return type of vpr::ReadableObject::readObject() and vpr::WritableObject::writeObject() impact code written for sharing application-specific data in a cluster. These changes were made as part of VPR 1.1.5, so all code built against versions of VPR prior to this must returnvpr::ReturnStatus in their override of these methods. For VPR 1.1.5 and beyond, the return type must be void. The following shows an example of how to write code that will work with VPR 1.0, 1.1, and 2.0. Here, the VPR 1.1.5 version number is encoded as 1001005, and the encoded version can be queried from the __VPR_version preprocessor symbol defined in vpr/vprParam.h.
#include <vpr/vprParam.h>
#include <plugins/ApplicationDataManager/UserData.h>
class MyType : public vpr::SerializableObject
{
public:
#if __VPR_version < 1001005
vpr::ReturnStatus
#else
void
#endif
readObject(vpr::ObjectReader* reader)
{
// Read object from reader...
#if __VPR_version < 1001005
return vpr::ReturnStatus();
#endif
}
#if __VPR_version < 1001005
vpr::ReturnStatus
#else
void
#endif
writeObject(vpr::ObjectWriter* writer)
{
// Write object to writer...
#if __VPR_version < 1001005
return vpr::ReturnStatus();
#endif
}
};
| |||||||
ThreadsThe use ofvpr::ThreadFunctor has been replaced by the much more powerful and flexible Boost.Function. In VPR 1.0, threads were created using one of the following approaches:
| ||||||||
| Line: 17 to 58 | ||||||||
// Using a member function. MyType* my_obj = new MyType(); | ||||||||
| Changed: | ||||||||
| < < |
vpr::ThreadMemberFunctor* functor = | |||||||
| > > |
vpr::ThreadMemberFunctor | |||||||
|
new vpr::ThreadMemberFunctor | ||||||||
| Line: 72 to 113 | ||||||||
| } | ||||||||
| Added: | ||||||||
| > > |
These changes were made in VPR 1.1.16 (encoded as 1001016). Furthermore, in VPR 1.1.31, the use of vpr::ReturnStatus in vpr::Thread was replaced by exception handling, and vpr::Thread::isValid() was removed. The following example shows how one might write code to work with VPR 1.0, 1.1, and 2.0. This could be simplified by eliminating VPR 1.1 from the mix and comparing __VPR_version only against 2000000 (the encoding of the VPR 2.0.0 version). In that case, the clause for versions between 1.1.16 and 1.1.31 in MyClass::startThread() would be unnecessary.
#include <vpr/vprParam.h>
#include <vpr/Thread/Thread.h>
class MyClass
{
public:
MyClass()
: mRunning(false)
#if __VPR_version < 1001016
, mThreadFunctor(NULL)
#endif
, mThread(NULL)
{
}
~MyClass()
{
if ( mRunning )
{
stopThread();
}
if ( NULL != mThread )
{
delete mThread;
mThread = NULL;
}
#if __VPR_version < 1001016
if ( NULL != mThreadFunctor )
{
delete mThreadFunctor;
mThreadFunctor = NULL;
}
#endif
}
bool startThread()
{
#if __VPR_version < 1001016
mThreadFunctor =
new vpr::ThreadMemberFunctor<MyClass>(this,
&MyClass::run,
NULL);
mThread = new vpr::Thread(mThreadFunctor);
return mThread->isValid();
#else
bool started(false);
try
{
mThread =
new vpr::Thread(boost::bind(&MyClass::run,
this));
// Handle versions between 1.1.16 and 1.1.31.
#if __VPR_version < 1001031
started = mThread->isValid();
#else
started = true;
#endif
}
catch (vpr::Exception& ex)
{
std::cerr << ex.what() << std::endl;
}
return started;
#endif
}
void stopThread()
{
mRunning = false;
if ( NULL != mThread )
{
mThread->join();
}
}
private:
void run(
#if __VPR_version < 1001016
void*
#endif
)
{
mRunning = true;
while ( mRunning )
{
// Do work...
}
}
bool mRunning;
#if __VPR_version < 1001016
vpr::ThreadMemberFunctor<MyClass>* mThreadFunctor;
#endif
vpr::Thread* mThread;
};
| |||||||
Synchronization PrimitivesUsing Flagpoll | ||||||||
| <<O>> Difference Topic MigratingToVrjTwoTwo (r1.1 - 27 Oct 2006 - PatrickHartling) |
| Line: 1 to 1 | ||||||||
|---|---|---|---|---|---|---|---|---|
| Added: | ||||||||
| > > |
Porting from VR Juggler 2.0 to 2.2VPR Interface ChangesThe VR Juggler Portable Runtime (VPR) has undergone extensive work to improve error reporting through the use of exceptions (derived fromvpr::Exception) rather than the clumsier use of vpr::ReturnStatus. Methods in VPR 1.0 classes that used to return vpr::ReturnStatus (generally) now have a void return type and report errors by throwing exceptions. In some cases, the use of vpr::ReturnStatus as the return type was replaced by returning a bool and throwing exceptions to report critical errors. This was only done for cases where an operation can "fail" under standard usage; exceptions are used to report exceptional cases.
I/O ClassesThreadsThe use ofvpr::ThreadFunctor has been replaced by the much more powerful and flexible Boost.Function. In VPR 1.0, threads were created using one of the following approaches:
// Using a member function.
MyType* my_obj = new MyType();
vpr::ThreadMemberFunctor* functor =
new vpr::ThreadMemberFunctor<MyType>(my_obj,
&MyType::threadFunc,
NULL);
vpr::Thread* thread = new vpr::Thread(functor);
// Using a non-member function or a static member function.
vpr::ThreadNonMemberFunctor* functor =
new vpr::ThreadNonMemberFunctor(threadFunc, NULL);
vpr::Thread* thread = new vpr::Thread(functor);
The signature of the thread function passed to the functor had to have a void return type and take a single void* parameter (that often went unused).
In VPR 2.0, the thread function can take any number of parameters, though it must still have a void return type. (The boost::function<T> type instantiation is boost::function<void ()>.) This is possible by using boost::bind(). boost::bind() must also be used for creating thread functors for member functions. The following shows how to do the equivalent of the above VPR 1.0 thread creation mechanisms:
// Using a member function.
MyType* my_obj = new MyType();
vpr::Thread* thread =
new vpr::Thread(boost::bind(&MyType::threadFunc, my_obj));
// Using a non-member function. vpr::Thread* thread = new vpr::Thread(threadFunc);Clearly, this new approach is much simpler and avoids a potential (and all-too-common) memory leak wherein the heap-allocated vpr::ThreadFunctor instance would not get deleted.
As noted, boost::bind() can be used to allow for thread functors that take any number of arguments. For example, consider these (somewhat contrived) cases:
void threadFunc(const int val,
std::vector<SomeClass>& vecRef)
{
for ( int i = 0; i < val; ++i )
{
vecRef.push_back(SomeClass(i));
}
}
void createThread(const int val)
{
std::vector<SomeClass> vec;
vpr::Thread* thead =
new vpr::Thread(boost::bind(threadFunc,
val, boost::ref(vec));
thread->join();
std::cout << vec.size() << std::endl;
}
Synchronization PrimitivesUsing Flagpoll-- PatrickHartling - 27 Oct 2006 | |||||||
| Topic MigratingToVrjTwoTwo . { View | Diffs | r1.4 | > | r1.3 | > | r1.2 | More } |
|
Revision r1.1 - 27 Oct 2006 - 19:52 - PatrickHartling Revision r1.4 - 15 Nov 2006 - 15:32 - PatrickHartling |
Copyright © 1999-2008 by the contributing authors.
All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding VRJ Wiki? Send feedback |