Many objects in object-oriented programming have an
identity, such as a file, a front-panel object or a hardware device.
These objects cannot be modelled using present LabVOOP (LabVIEW Object Oriented Programming) objects as
LabVOOP objects gets copied as wire is branched; multiple different
wires cannot all represent a single object. This issue has been
irritating the community of LabVIEW users since the release of LabVOOP
a few months ago.
It seems that there is a huge demand for
objects with unique identity i.e. by-reference objects in LabVIEW. The
central problem why LabVOOP propably doen't have these objects is the
difficulty in implementing synchronized access to these objects from
multiple parallel threads. The problem of synchronized access can be
divided into two different separate topics. First how the
sychronization should be implemented in LabVIEW runtime engine. Second
how this synchronization mechanism should be visible to the developer.
I'd like to start this thread to discuss these two issues.
Synhronization under the hood
Traditionally
people talk about locking of an object and about get-modify-set pass
when accessing the object. Locking is traditionally done by acquiring a
mutex for an object, modifying the object and releasing the mutex so
that other threads can access the same object instance. This is how
inter-thread synchronization is traditionally done. However, besides
the mutex based locking, the computer science community has innovated
also different kinds of methods on synchronizing the access to objects.
One way to get object-level synchronization is modify the
runtime engine so that it only allows a single method of a synchronized
object to run at any time. This mechanism of syncrhonization is
implemented in programming languages like
O'Haskell, which is a Haskell
variant with object orirented features.
Also different
transactional mechanisms[
1,
2] have been successful. In transactional
mechanisms multiple threads are allowed to access a synchronized object
simultaneously. As each method accessing an object commits their
changes, they verify that no other object has modified the object
simultaneously in a manner than would break the transaction. If such a
modification has occurred, everything is rolled back. Transactional
mechanism do not suit to every possible situation as not everything can
be rolled back. For example it's hard to roll back an action that
somehow modifies the physical world.
User experience of synchronizationHow
the synchronization is generally implemented in LabVIEW shouldn't be
directly visible to the developer end-user. The developer should
understand the general concepts of synchronization to take full
advantage of it, but in general the synhronization mechanism should be
integrated directly to development environment. There should in general
be no need to acquire a mutex by calling acquire mutex node but instead
the end-user should be able to specify which data needs synhronized
access in more sophisticated way.
In the following I propose a
mechanism of integrating the synchronized access of by-ref objects to
the development environemnt of LabVIEW. The proposal is very
preliminary but I hope it breaks the ice and the community would start
innovating in how should NI implement the syncrhonization support in
the user interface of LabVIEW.
Wire level synchronizationOnly
methods can access object private data members. In synchronized access
to the object, it's the methods accessing the private data members that
need to be synchronized. The private data members are accessed by
applying unbundle node to the class wire and data is written back to
the object using bundle node.
What I propose is the following.
An unbundle node could either be normal or "synchronized". A
synchronized unbundle would guarantee the access to the private data
members in synchronized manner. All data wires originating from
synchronized unbundle would be of synchronized type, in a little
similar manner as a dynamic dispatch wire is of special dynamic
dispatch type. Such a wire must evetually be connected to a bundle
node. When the wire is bundled back to the originating object, the
synchronization requirement is released.
These synchronized
wires would look somewhat different from normal wires so that the
developer instantly knows that the wire is synchronized. The developer
can branch the wire, but only one wire branch can own the synchronized
type. The developer could easily select which wire would be
syncrhonized by Ctrl+clicking the wire. Such a wire can be considered
as a combination of a data and a mutex, even though mutexes don't need
to be the underlying synchronization method. The wire just guarantees
that there is a mechanism in the runtime engine that makes sure the
access to the wire data is synchronized.
There is a need to wire
data originating from a non-synchronized wire to a synchronized wire so
that it can replace the private data member of the class. This is
accomplished with a new node similar to bundle node, that would allow
replacing the data in a syncrhonized wire with some data originating
from a non-synchronized wire.
The synchronized wire can be
connected to a front panel controls of special syncrhonized type. This
way the synchronized wire can originate from a method and allow passing
the synchronized data to the calling VI and back to another method.
This is practical for example in a situation when the developer wants
to run different analyzes to a data class but don't want to rewrite all
the existing data analysis tools as class members. So the developers
writes a syncrhonization acquiring getData method that let's the
calling VI to access the syncrhonized data. Then the developer passes
this data to an analysis VI and passes the result back to a setData
method that writes the result back to the class wire.
There
will probably be technical problems in allowing the user to connect
such a synchronized wire to all existing VIs since these VIs. Therefore
the programming model for all nodes that do not support such
synchronized wires will be branching the wire and passing the
non-synchronized wire branch to the node and then bundling the result
back to the synchronized wire.
To increase performance and
decrease unnecessary buffer copies when a syncrhonized wire is
branched, if the syncrhonized wire continues directly to the new bundle
synchronized wire node, no buffer copy is made.
Discussion
The
syncrhonized access to a by-ref LabVOOP objects can be implemented in
multiple ways by National Instruments. The synchronized access should
be divided to two different and independent parts: 1) the user
experience of synchronization and 2) the runtime engine synchronization
mechanisms. As LabVOOP objects have special properties compared to
other LabVIEW data types, optimal user experience can be gained by
designing the user experience specifically for LabVOOP objects. From
user experience point-of-view this syncrhonization mechanism may not
work for other data types. Separating object syncrhonization from
synchronization of other data types is advantageous also for other
reasons. Due to the fact that object data can only be accessed via
object methods, more advanced synchronization methods may be used with
objects than can be used with other data types. O'Haskell
synchronization implementation is an example of this. Integrating the
synchronization directly to the user interface allows NI to change the
mehcanisms under the hood, when computer science comes up with more
advanced methods. Therefore NI could begin with traditional and quite
easy mutex-based synchronization and later move to more advanced
perhaps transaction based syncrhonization methods or even combinations
of multiple different methods.
I hope this topic generates
discussion that would help NI to implement an excellent synchronization
mechanism in LabVOOP. I hope that all talented individuals in the
community participate this discussion to help NI to reach this goal. I
also hope that if you just have time, it would be great if you could
surf the computer science resources to find out what kinds of new
techniques there exists for synchronizing access to shared resources. A
Large community may find much more innovative solutions than a few engineers at NI. Let's give NI the power of open source design
--
Tomi Maila