Jump to content


- - - - -

Singleton Design Pattern


35 replies to this topic

#1 tjs157

    I've come back for more.

  • Members
  • 2 posts

Posted 25 November 2009 - 07:08 PM

Has anyone implemented a better example of the singleton pattern than the one that ships with LV. I really don't like the use of a library to hide the class. It requires a method in the library and then one on the class to actually do the work. This seems redundant, I would prefer to see the details of the queue hidden in the class and not require the use of the library.

Any ideas??

#2 MikaelH

    Extremely Active

  • Premium Member
  • 454 posts
  • Location:Sydney
  • Version:LabVIEW 2010
  • Since:1996

Posted 25 November 2009 - 08:29 PM

Hi

I'm a GDS fan (no wounder Posted Image ), so I just right click in the Project Tree amd selectes New->GOOP Class (Using The Endevo's Reference based provider).
Then I just select a singelton class type, it's so easy :-)
Attached Image: New_GoopClass.png
Attached Image: CreateSingeltonClass.png

..one advantage I like about this template (or any GDS class templates) is that if there is a new version of the class template I've used, the GDS toolkit can automatically update the class to the new template.

Cheers,
Mikael

#3 Aristos Queue

    LV R&D: I write C++/# so you don't have to.

  • Premium Member
  • 2,324 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 26 November 2009 - 04:35 AM

Ok. I really want to know: Why do you need Singleton? What are you using it for? I implemented the example that ships with LabVIEW because lots of people wanted to see some implementation for it. But I honestly am not sure why you want it in LabVIEW. In C++ it makes perfect sense, but not so much in LabVIEW. At least, that's my opinion. Now, you can ask why I would think a construct would be useful in one language and useless in another... I have an answer, but I'd rather not share it at the moment. First I'd like to know what you're doing with these Singleton classes. I have yet to be convinced that it is a useful pattern in LabVIEW.

#4 MikaelH

    Extremely Active

  • Premium Member
  • 454 posts
  • Location:Sydney
  • Version:LabVIEW 2010
  • Since:1996

Posted 26 November 2009 - 09:22 AM

Attached Image: Singelton.png
Singleton or not…
I often use Singleton classes, it might be because I’m lazy wiring the class wire through all my application.

Here is a brief description of why I use singletons.

This is how my standard implementation of my manufacturing rigs looks like.
I use a top level VI, and some singleton classes and a bunch of instrument driver classes.

Let’s look at the current rig I’m working on.
This rig should:
1. Place, align and glue 3 optical components on the DUT.
2. Every component is held by a motorized stage with 4-5 axis.
3. Every stage has about 7-10 additional digital IOs
4. There is an over all vision system with 2 cameras with different lighting controls.
5. There is an additional optical measurement system I’m using for alignment.

In total it’s about 50 IOs in the system from simple position sensors, pneumatic values to 13 motorized stages, cameras, glue dispense systems and other more advanced measurement system.

So where should I start when implementing a large system like this?

I start by looking at the system from an operator’s perspective, what can I see?
I see 3 separate motor stages.
I see a camera and lighting arm, holding 2 cameras and some lamps.

So I decide to create 3 classes, one for every motor stage, this is because they look completely different and hold different components.
I name the classes after what component they are holding.
So one stage will be called “Mirror”-class, and I choose to use a singleton class here.
So why do I use a singleton class?
I know that I will only use one of these objects in my application, but the main reason is that I don’t want to clutter the block diagram of my Main VI, that is going to use this object ;-)

This “Mirror”-class will aggregate all instrument objects it needs, e.g. 4 motion control motors.
This class will encapsulate all functions I might need to perform on the Mirror component.
I will have a public method (a method that my main VI will call) named “Pick up and place mirror at initial location”, and also one called “Cure Mirror Glue”.
These methods will be a bit abstract and I let the method figure out how to perform these actions.

That way I get a good abstraction level, and it’s easy to follow the application flow in my Main VI.

I never allow my main VI to access the instruments direct, so I’m forced to go through an abstraction layer.

By using this approach, I can break down the complex system into smaller solvable parts, in my case I use classes.
And for this project I use only singleton classes in my application component layer that abstracts the driver layer from the main VI.

Attached Image: ClassDiagram1.PNG

Cheers,
Mikael

#5 Mark Yedinak

    Extremely Active

  • Members
  • PipPipPipPip
  • 412 posts
  • Location:Chicago, IL
  • Version:LabVIEW 2010
  • Since:1997

Posted 10 December 2009 - 02:29 AM

I can think of several good uses of a singleton class. For starters the application can have a log file. We will want to add entries to the log file anywhere in the application, including in parallel tasks. Now, let's say we give the user the ability to change the name of the log, modify attributes which control what to log, or even if the log itself generates new files based on time or size. I have just named several parameters that control the log that must be shared by all instances of the log. If this needs to be shared why not have a singleton of the class. After all, there is only one log file. Using the current data flow only classes that exist as soon as the wire splits the attributes are duplicated and a change on one branch of the wire will not affect an instance on another branch. In addition to a log any time we have a single instance of something in the system such as a piece of hardware, a network connection or other physical interface we have good candidates for singletons. There are ways to kind of achieve this in LabVIEW such as your example but it would be easier on the programmer if this could be handled automatically if the instance of the class is declared a singleton.
---
Mark Yedinak - Certified LabVIEW Architect and LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot

#6 Daklu

    Learning LabFu Daily

  • Premium Member
  • 1,493 posts
  • Location:Seattle
  • Version:LabVIEW 2010
  • Since:2006

Posted 11 December 2009 - 03:50 PM

Mark, do you create new log file singletons for each application or do you have a general one you reuse?
Certified LabVIEW Architect
Good software is an investment. Bad software is an expense. Choose wisely.

Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

There are two secrets to success:
Secret #1 - Never tell everything you know.

#7 Tim_S

    Extremely Active

  • Members
  • PipPipPipPip
  • 439 posts
  • Location:Michigan
  • Version:LabVIEW 2011
  • Since:1994

Posted 15 December 2009 - 06:27 PM

I think the use of the queue for the singleton object is a good choice. I have implemented it is a two-element queue instead and had two copies of the same data in the queue. Locking the queue involved dequeueing one element. Canceling the lock involved reading the remaining entry and writing it back to the queue. I used the lossy enqueue to write new value to the singleton object.

I have used singleton objects when the object will have global affect based on changes from any location in the program. Offhand I can think of logging, error management, security, resource interface/daemon and configuration settings as times I have or might use a singleton object.
Tim

"If this was easy our kids would be doing it." - Coworker

#8 Aristos Queue

    LV R&D: I write C++/# so you don't have to.

  • Premium Member
  • 2,324 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 20 December 2009 - 03:40 PM

View PostTim_S, on 15 December 2009 - 06:27 PM, said:

I have implemented it is a two-element queue instead and had two copies of the same data in the queue.
Then this wasn't a singleton. By definition, a singleton class allows only one copy of the data to exist anywhere in memory ever. It should be impossible to create a second copy. If you can create a second copy, it's not a Singleton. That's just a reference to an object.

#9 Black Pearl

    Extremely Active

  • Members
  • PipPipPipPip
  • 410 posts
  • Location:Freiburg, Germany
  • Version:LabVIEW 7.1
  • Since:2002

Posted 20 December 2009 - 04:32 PM

I encountered the word 'fewton' on wikipedia yesterday (it indeed is a 'singletone'-style object that has a limited number of maximum instances >1).

Felix

#10 Norm Kirchner

    The 500 club

  • NI
  • 709 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 20 December 2009 - 04:48 PM

View PostBlack Pearl, on 20 December 2009 - 04:32 PM, said:

I encountered the word 'fewton' on wikipedia yesterday (it indeed is a 'singletone'-style object that has a limited number of maximum instances >1).

Felix


Well that's no surprise, you probably just added it yourself ;)

I love wikipedia

j/k

#11 Aristos Queue

    LV R&D: I write C++/# so you don't have to.

  • Premium Member
  • 2,324 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 20 December 2009 - 04:53 PM

View PostBlack Pearl, on 20 December 2009 - 04:32 PM, said:

I encountered the word 'fewton' on wikipedia yesterday (it indeed is a 'singletone'-style object that has a limited number of maximum instances >1).
I thought a fewton was something you slept on. :-)

#12 Daklu

    Learning LabFu Daily

  • Premium Member
  • 1,493 posts
  • Location:Seattle
  • Version:LabVIEW 2010
  • Since:2006

Posted 20 December 2009 - 05:05 PM

View PostAristos Queue, on 20 December 2009 - 03:40 PM, said:

Then this wasn't a singleton. By definition, a singleton class allows only one copy of the data to exist anywhere in memory ever. It should be impossible to create a second copy. If you can create a second copy, it's not a Singleton. That's just a reference to an object.

I read his description as an internal implementation of a singleton object. As long as any class wire accesses the same chunk 'o data it is essentially a singleton regardless of the internal implementation. The two copies on the queue just provide a convenient way for him to cancel a lock without having to requeue the data, as you would have to do with a single element queue.


View PostBlack Pearl, on 20 December 2009 - 04:32 PM, said:

I encountered the word 'fewton' on wikipedia yesterday (it indeed is a 'singletone'-style object that has a limited number of maximum instances >1).

I searched... no joy.

View PostAristos Queue, on 20 December 2009 - 04:53 PM, said:

I thought a fewton was something you slept on. :-)

Sleep? More like a medieval torture device.
Certified LabVIEW Architect
Good software is an investment. Bad software is an expense. Choose wisely.

Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

There are two secrets to success:
Secret #1 - Never tell everything you know.

#13 Black Pearl

    Extremely Active

  • Members
  • PipPipPipPip
  • 410 posts
  • Location:Freiburg, Germany
  • Version:LabVIEW 7.1
  • Since:2002

Posted 20 December 2009 - 06:18 PM

It is on the german wikipedia in the article about design patterns (right after singleton)

http://de.wikipedia....rzeugungsmuster

In the artcle about Singleton, another variant is mentioned: the Multiton.

Another ressource is the following implementation of the Fewtone (german text, but implementation is java/english)
http://www.junit-buc...doc/fewton.html

I also found some real examples why you want to have a Fewton. If you have a limited ressource available (network bandwidth), you want to limit the number of processes (number of downloads, torrents ...) that access these, but to a number >1.

Felix

#14 Daklu

    Learning LabFu Daily

  • Premium Member
  • 1,493 posts
  • Location:Seattle
  • Version:LabVIEW 2010
  • Since:2006

Posted 21 December 2009 - 08:11 AM

View Posttjs157, on 25 November 2009 - 07:08 PM, said:

Any ideas??

All right... here's an object I created (LV 2009) to help test out my Interface Framework and make sure it can handle various ways data can be stored. It implements the following techniques to achieve different kinds of data persistence:

ByVal Data - Plain old vanilla Labview
ByRef Data - Data Value Reference
ByRef Data - Unnamed Queue
Static Data - Global Variable
Static Data - Named Queue
Static Data - Functional Global

You can look to see how I implemented them. Beware: I didn't bother to include any locking behavior as I don't need it for what I'm doing. Race conditions will likely pop up all over the place if you use these exact implementations. I'll happily answer any questions, but if you shoot yourself in the foot you can't say you weren't warned. Posted Image

Did I mention I really like vanilla?

View PostBlack Pearl, on 20 December 2009 - 06:18 PM, said:

I also found some real examples why you want to have a Fewton. If you have a limited ressource available (network bandwidth), you want to limit the number of processes (number of downloads, torrents ...) that access these, but to a number >1.

I can see why you'd want a limited number of certain kinds of objects. Is this limitation something they try to build directly into the class? If so, that seems like an overly-complex way to go about it. Much easier to just create a regular old by-val object to manage a single process and then create a distributor object that has an array of n process objects and sends them off to clients that request them.

Attached File(s)


Certified LabVIEW Architect
Good software is an investment. Bad software is an expense. Choose wisely.

Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

There are two secrets to success:
Secret #1 - Never tell everything you know.

#15 Black Pearl

    Extremely Active

  • Members
  • PipPipPipPip
  • 410 posts
  • Location:Freiburg, Germany
  • Version:LabVIEW 7.1
  • Since:2002

Posted 21 December 2009 - 09:12 AM

Don't forget that the vanilla way in most text based OOP languages is the by-ref design. These cowboys like to shoot around with pointers instead of keeping all safe on the wire.

If I were to create a Fewton'O'Eight, I also would consider a queue, create 8 objects and store them in the queue. Whenever a request is received, dequeue one of these objects. Whenever a object is returned, enqueue it again. I think this approach is simpler than the array (because the objects are not ordered).

Felix

#16 Daklu

    Learning LabFu Daily

  • Premium Member
  • 1,493 posts
  • Location:Seattle
  • Version:LabVIEW 2010
  • Since:2006

Posted 21 December 2009 - 05:41 PM

View PostBlack Pearl, on 21 December 2009 - 09:12 AM, said:

These cowboys like to shoot around with pointers instead of keeping all safe on the wire.

I know... apparently their mommas never taught them it's not polite to point. Posted Image


View PostBlack Pearl, on 21 December 2009 - 09:12 AM, said:

I think [using queues] is simpler than the array

Yep, you're right.

One potential downside of using a distributor class is that it's relies on cooperative clients that send the object back to the distributor when they are done with it. If a client hangs or forgets to return it you end up losing at least one, and potentially more, of your process objects. If you have a large application with many clients requesting process objects, forgetting to return one of them would show up as slowly decreasing performance over time as the application runs.

I've been wondering if there's a good way to prevent that from happening. I can't think of any way for the distributor object to forcefully recall an object without relying on client-side implementation. If the process objects are active objects you could implement a self-destruct mechanism that operates either from an internal watchdog timer or on a message from the distributor. Once the object has been destroyed the distributor could create a new process object and put it on the internal queue. I haven't prototyped this so I don't know how messy it would get or if it's even feasible.

I'm not sure how well a self-destruct message would work with vanilla objects. In principle you wouldn't want to create a replacement process object until you've confirmed that the old process object was destroyed, but the client controls the object's execution and it's possible that object will never execute again.

View PostBlack Pearl, on 21 December 2009 - 09:12 AM, said:

If I were to create a Fewton'O'Eight...

My point was that whereas a singleton is something that is built into the class itself, a fewton that is implemented using a distributor is an artifact of the way the objects are being managed. It could be a useful term to describe the programmer's intent, but I believe it is incorrect to describe a class as a fewton. (Unless, of course, the class itself limited the number of objects that could be created. I have no idea what that would look like in Labview though.)
Certified LabVIEW Architect
Good software is an investment. Bad software is an expense. Choose wisely.

Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

There are two secrets to success:
Secret #1 - Never tell everything you know.

#17 Daklu

    Learning LabFu Daily

  • Premium Member
  • 1,493 posts
  • Location:Seattle
  • Version:LabVIEW 2010
  • Since:2006

Posted 21 December 2009 - 05:58 PM

View Posttjs157, on 25 November 2009 - 07:08 PM, said:

I really don't like the use of a library to hide the class.

Incidentally, the singleton example that ships with Labview is a good example of a distributor that manages n vanilla byref objects for clients. The examples I posted are ways to build singleton behavior into a class itself. In general following the distributor pattern provides more flexibility; you can always make a byref object into a singleton but you can't make a singleton into a byref object.
Certified LabVIEW Architect
Good software is an investment. Bad software is an expense. Choose wisely.

Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

There are two secrets to success:
Secret #1 - Never tell everything you know.

#18 Aristos Queue

    LV R&D: I write C++/# so you don't have to.

  • Premium Member
  • 2,324 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 21 December 2009 - 10:34 PM

*
POPULAR

In LV 2009, this is how I would recommend that the Singleton pattern be implemented:
Attached File  AQSingleton.zip (42.97K)
Number of downloads: 284
No wrapping library. No replication of VIs caused by having public wrappers and private implementations. No excessive copy overhead. And, yes, thread safety for parallel public calls.

This demo class implements three public functions: Set Path, Append Path (which does a read-modify-write) and Get Path.
Attached Image: SingletonImage.png

Note that there is one minor issue with this implementation *if* (and only if) you have multiple top-level VIs all using the same central storage and the one that accesses the global first quits before the others are ready. The workaround solutions for that are ... problematic. It is in the set of "holes in the LV language" that we've been slowly patching o'er these many years.

#19 Daklu

    Learning LabFu Daily

  • Premium Member
  • 1,493 posts
  • Location:Seattle
  • Version:LabVIEW 2010
  • Since:2006

Posted 22 December 2009 - 01:12 PM

View PostAristos Queue, on 21 December 2009 - 10:34 PM, said:

In LV 2009, this is how I would recommend that the Singleton pattern be implemented:

Very nice. Posted Image

Is this going to be included as a shipped example in 2010?

(I'm curious, is that implementation something you've been sitting on for a while waiting to see if the community would 'discover' it or did you actually have to sit down and think about it for a while?)
Certified LabVIEW Architect
Good software is an investment. Bad software is an expense. Choose wisely.

Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

There are two secrets to success:
Secret #1 - Never tell everything you know.

#20 Aristos Queue

    LV R&D: I write C++/# so you don't have to.

  • Premium Member
  • 2,324 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 22 December 2009 - 02:07 PM

View PostDaklu, on 22 December 2009 - 01:12 PM, said:

(I'm curious, is that implementation something you've been sitting on for a while waiting to see if the community would 'discover' it or did you actually have to sit down and think about it for a while?)
It's been in my head in theory, but I hadn't had time to type it out. I declined to make it a shipping example in LV 2009 because the DVRs were new and I needed to see how they'd be accepted (or not) by the community. Including it (a cleaned up, more commented version of it) in 2010 is probable if the folks here think it solves the issues.