Singleton_pattern and Thread Safety

J

Joshua Maurice

Yes, misuse of singletons can be a disaster, a maintenance nightmare.
Have you ever been forced to weed through all the uses of such a "kewl
global variable" just to figure out wtf will happen if there are two
of them, because of course now you need two of them?

The idea that a programmer can know that there /must never ever/ be
more than one instance of a class T is, to be perfectly frank, nearly
laughable.

Now, of course, one may know that at this particular time we need
a /common/ shared instance but this is easily achieved with a non-
intrusive smart "pointer" template such as the singleton template
Leigh gave or the very similar (though having more features)
"common" template of mine. For example my

   common<Foo> foo ;

is a kind of smart pointer to a common instance of Foo. These days
I can think of absolutely no, nada, zero reasons why I would want to
pollute a Foo type with intrusive "singleton" scaffolding. If anyone
knows of good reasons for intrusive singletons please enlighten me.

KHD

PS. I think singleton is so heavily abused because 1) the name
sounds kewl 2) it constrains usage of the class and even if that
constraint is useless programmers love to naively force their will
on other programmers 3) it's famous so you can throw it around as
a buzzword and seem smart 4) it also happens to provide a global
variable replacement and one that has been /approved/ by all the
kewl kids 5) you are mocked as a "C" programmer if you are honest
and just use a plain global variable (or free function).

With respect, if you are abstracting some system resource, then it
makes sense to be "global" in the colloquial sense and to use a
singleton. You can't change the fact that you have only one disk (or
disk subsystem), nor can you change the fact that you have only 1 OS
and process / thread scheduler, and so on.

However, I agree that most uses of singleton are not that.
 
B

Bart van Ingen Schenau

On 14/12/2010 21:59, Ian Collins wrote:

It is a leak.  If it wasn't a leak the OS wouldn't have anything to
deallocate during process cleanup.

By this definition, all statically allocated variables create memory
leaks as well, because you have to rely on the OS to cleanup their
memory.
And the memory used for the code is also leaked, because that must
also be cleaned up by the OS.

Bart v Ingen Schenau
 
G

gwowen

Stack space is never "leaked" however resources allocated by objects on
the stack can be leaked.  

Why not? Is this part of your definition of "leak"? In both cases,
whether the memory is dynamically allocated or stack allocated, the
pages of physical memory are returned to the system at process-
teardown *by the OS*. I'll ask you again, unless its in the
definition ("i.e. LEAK can only apply to dynamically reclaimed at
process exit") what's the qualitative difference between how the OS
handles dynamically allocated variables and automatically allocated
memory?

PS: If dynamic memory is leaked on abort, what happens if I write a
program that does "malloc();memset();abort();" and repeatedly run it?
Will I bring the system to its knees?
 
K

Keith H Duggar

With respect, if you are abstracting some system resource, then it
makes sense to be "global" in the colloquial sense and to use a
singleton. You can't change the fact that you have only one disk (or
disk subsystem), nor can you change the fact that you have only 1 OS
and process / thread scheduler, and so on.

However, I agree that most uses of singleton are not that.

Such a hypothetical C++ object is not a "disk" nor is it an "OS"
etc. It is an /interface/ to said "disk" etc. I don't see how one
can foresee all possible future needs and determine that one should
/restrict/ the multiplicity of such an /interface/ to 1. And then
intimately engrain this unnecessary assumption into the code. In
my mind such "must be only one" thinking results from classic
fallacy of conflating the /physical/ with the /logical/.

What happens when you want to instantiate an interface to a some
other virtual "disk" in addition to the current one-and-only-one
physical "disk"? What happens when you want to run a virtual OS
(for example emulators) along side the metal OS? What happens
when you want a dedicated thread scheduler for each cell? Or
even just a custom green thread scheduler?

What good reason does one have to make the above so much more
difficult by deeply enshrining "singleton" assumptions in the
code? Seems completely short sighted and unnecessary busy work
to be honest.

And, no, this is not hypothetical speculation on my part. I am
reflecting on /real world actual/ nightmares I've run into exactly
because I had to generalize code to use multiple event schedulers,
storage interfaces, etc that were all oh-so-reasonably constrained
singletons because "obviously" there must be only one of them.

KHD
 
G

gwowen

A leak is an explicit allocation that is not paired with an explicit
deallocation.  

OK. That's your definition. Here's another one, taken from the first
line of the Wikipedia article called "Memory Leak": "A memory leak,
in computer science (or leakage, in this context), occurs when a
computer program consumes memory but is unable to release it back to
the operating system"

Here's FOLDOC's: "A leak in a program's dynamic store allocation logic
that causes it to fail to reclaim memory in the heap after it has
finished using it, eventually causing the program to fail due to lack
of memory."

Here's TechTerms: "A memory leak is like a virtual oil leak in your
computer. It slowly drains the available memory, reducing the amount
of free memory the system can use."

Do you accept any of these definitions as equally valid as yours, and
if not, what authority has declared your definition the correct one?
A leak is a bug.

Even when it has does not change the preconditions, result or
postconditions of the program? Weird definition of a bug. How would
I write a unit test that detected it?

Incidentally, by your definition, GNU Libc is extremely, and
deliberately, buggy. Good luck filing those bug reports.
 
G

gwowen

Here's Microsoft's definition:
....

Note Microsoft explicitly say that a leak is a bug and that a singular
leak (what I am talking about) is still a leak; the fact that this kind
of leak is mostly harmless does not detract from the fact that it is
still a leak.

And here's Apple's

"Memory leaks are blocks of allocated memory that the program no
longer references. Memory leaks are bugs and should always be fixed."
-- http://developer.apple.com/library/...ual/ManagingMemory/Articles/FindingLeaks.html

Again, I'll ask you: why are your definitions correct and the others
wrong?
 
G

gwowen

So Microsoft's opinion doesn't count in your world?  

Absolutely it does. But when other opinions are available, only an
unthinking person would take any single opinion as if it were revealed
truth. Personally, I prefer hearing all the opinions and making a
nuance judgement. It's a little harder, but you tend not to come
across as a total berk.
Singular leaks are still leaks.

<unthinking_idiot>So Apple's opinion doesn't count in your world?</
unthinking_idiot>

According to Apple, if the allocation is reachable at process
termination time, its not a leak. A programming idiom that can be
proved not to affect a program's preconditions, postconditions or
results is not defect, for any meaningful definition of the term
"defect".
One can argue that the pointer in question becomes unreachable during
the C++ "termination" phase which happens before (and is therefore
distinct from) the OS process cleanup phase.

One can argue that. If one wishes to look like a fool who is twisting
in the wind, one absolutely *should* argue that. I look forward to
hearing you continue to do so.
 
G

gwowen

It is a singular leak; it is a leak; it is a bug.

So you keep saying. Unfortunately, repetition is not a persuasive
argument. If a programming idiom can be proved not to effect the
preconditions, postconditions and results, in what sense should the
program be considered defective? Seriously, can I have an answer more
persuasive than "Microsoft say so (although Apple don't)."
I have already shown how this singular leak can become an progressive
leak if it is present in a "plugin" DLL.  If it was not a leak in the
first place it couldn't become a progressive leak.

[Leigh also wrote]:
The initial version was thread safe on the implementation I was coding it
for therefore my application would not contain any bugs waiting to happen..

See: you actually believe that bugs that can be proved have no effect
are *not actually bugs* but, it would appear, this rule only applies
to your own code.
 
G

gwowen

So you choose to reply by quoting me on an unrelated issue rather than
address the point I raise?  

The point you raised was "Microsoft agree with me". I've addressed
that with "many other equally credible sources disagree with you." If
you had another point, please feel free to express it, because I
couldn't determine what it might be.
"the leak issue is platform agnostic not platform specific."

No, it clearly isn't. If the OS tears down memory at process
termination, then having reachable-but-not-deallocated memory at
process termination *does not cause the program to produce incorrect
results, or violate its preconditions or postconditions*. If the OS
doesn't reclaim the memory, it absolutely is a leak, and a bug that
needs to be fixed. That's not platform agnostic in the slightest.

"A software bug is the common term used to describe an error, flaw,
mistake, failure, or fault in a computer program or system *that
produces an incorrect or unexpected result, or causes it to behave in
unintended ways*" - Wikipedia, again.
 
G

gwowen

How the OS handles a leak is irrelevant to the issue of whether it is a
leak.  The definition of what constitutes a leak transcends all
operating systems.  A leak is an explicit allocation that does not have
a matching explicit deallocation.

So you keep saying. And Microsoft seem to agree with you. But Apple
don't. Apple say its an allocation to which you no longer have a
reference.
Yes and a leak is a bug according to that definition

Really? In those cases where the OS reclaims memory at process
termination, what is the incorrect or unexpected result or unintended
behaviour?
 
G

gwowen

The unintended behaviour is the OS having to reclaim the memory;

I'm willing to bet everything I own that when James Kanze wrote his
singleton implementation, dodging the complexities of multi-threaded
cross-TU destruction order, by having the OS reclaim the memory was
NOT unintended. Quite the opposite, in fact. Hell, I'll wager that
he went out of his way to confirm that this would happen on every
platform on which his singleton would be used, and that this behaviour
was intended before so much as a single line of code was written.
 
J

Joshua Maurice

Stack space is never "leaked" however resources allocated by objects on
the stack can be leaked.  Dynamically allocated memory is leaked after
calling abort() however abnormal program termination is a special case
for which leaks are acceptable.

On Linux, stack space is created through mmap. If you do not call
pthread_join or pthread_detach exactly once per created thread, I can
assure you that the memory will leak, in the traditional sense.
 
I

Ian Collins

What good reason does one have to make the above so much more
difficult by deeply enshrining "singleton" assumptions in the
code? Seems completely short sighted and unnecessary busy work
to be honest.

And, no, this is not hypothetical speculation on my part. I am
reflecting on /real world actual/ nightmares I've run into exactly
because I had to generalize code to use multiple event schedulers,
storage interfaces, etc that were all oh-so-reasonably constrained
singletons because "obviously" there must be only one of them.

One project I worked on where we had a lot of singletons, they
represented real-time data and configuration values. There could only
be one of each, that was enshrined in the system design.

Representing a set of data as singletons my look hacky, but in a cycle
constrained embedded system, the performance advantages were considerable.
 
G

Garrett Hartshaw

So Microsoft's opinion doesn't count in your world? Singular leaks are
still leaks.

No, Microsoft's *opinion* (in fact anyone's *opinion*) does not count.
 
J

Joshua Maurice

You say Apple disagree with me on the definition of a leak?  From the
same page you linked:

"If you call malloc or any routine that allocates memory, you must
balance that call with a corresponding free."

End of discussion.

I'm trying to tease out what you really think. You presumably don't
think that "Leigh Johnston memory leak" must be avoided at all costs -
at least, I hope that.

Namely, do you call abort or use assert from anywhere but the end of
main with zero outstanding mallocs, news, etc.? Do you use the C
library, such as glibc, or whatever windows equivalent? I'm willing to
bet that there are memory allocations in there with no paired free
calls. Moreover, have you ever written for a POSIX system ever? That
requires the use of fork and exec (perhaps indirectly), which almost
certainly requires a "Leigh Johnston memory leak" for any use
whatsoever.

So, as you have written working code, I can assume that in some
contexts "Leigh Johnston memory leaks" are ok, such as the ones listed
above. Please stop me if you disagree, and please describe your
problems with my analysis thus far, because I would be quite lost if
you did disagree.

So, is it just that "Leigh Johnston memory leaks" which are under your
control must be prevented at all costs, and you make do with the
mistakes of others who wrote the C library, fork and exec, etc.? IMAO,
this would be rather pants-on-head retarded if you said yes here. I
would read a yes as: "The C library on all platforms has memory leaks,
but programs written against it do not run out of virtual space, nor
does the OS run out of commit space."

I really do like the libc example. libc is an excellent example of a
library which the writers know will be loaded at most once per
process. If some process attempts to load it multiple times, then all
bets are off. I think I agree with others that this appears to be the
sensible default position, and shared-objects which are loaded and
unloaded multiple times in a single process are more of a special case
which deserve special care. I'm not entirely satisfied with this
result, but the alternative appears to be to take issue with all win /
mac / unix implementations in existence which display no visible bugs,
which I also don't feel comfortable doing.

This almost feels like I need to invoke "Worse Is Better". I need some
time to think about how I would apply "Worse Is Better" to this
conversion, but it feels right to do so. A gut feeling if you will.
 
J

James Kanze

So you keep saying. And Microsoft seem to agree with you. But Apple
don't. Apple say its an allocation to which you no longer have a
reference.

And most practicing programmers use a more useful definition
than either: a leak is an allocation pattern which causes
unbounded memory use. The fact that there is still a pointer to
the memory doesn't stop it from being a leak, if you never use
the memory, and are constantly allocating new memory.
Really? In those cases where the OS reclaims memory at process
termination, what is the incorrect or unexpected result or unintended
behaviour?

A leak is a bug according to that definition. The problem is
that Leigh (and you, apparently) have redefined leak in a way
that it isn't a bug. (Unbound memory use is a bug. Regardless
of whether you still have a pointer to the memory or not.)
 
K

Keith H Duggar

One project I worked on where we had a lot of singletons, they
represented real-time data and configuration values.  There could only
be one of each, that was enshrined in the system design.

Representing a set of data as singletons my look hacky, but in a cycle
constrained embedded system, the performance advantages were considerable..

Please post an example of such a singleton and an associated
performance critical usage of it. (Obviously stripped down so
we don't see dozens of config variables and hundreds of lines
of code, but maintaining the essential structure of both the
singleton and the performance critical call site.)

KHD
 
G

gwowen

And most practicing programmers use a more useful definition
than either: a leak is an allocation pattern which causes
unbounded memory use.

"Most practicing programmers" ... based on what?
 
E

Ebenezer

"Most practicing programmers" ... based on what?


Probably based on experience. I think he's given a
practical definition that is the minimum of what you
have to prevent.

Brian Wood
Ebenezer Enterprises
 
G

gwowen

Probably based on experience.  I think he's given a
practical definition that is the minimum of what you
have to prevent.

It's a sound practical definition, and one I'd kinda endorse (modulo
certain complaints about the word "unbounded"). Like "bug" itself,
trying to pin it down with a single prescriptive definition is
pretty. Personally, I'd go vaguer: "A memory leak is what you have
when deficiencies in your programs memory management cause so much
memory to be unnecessarily allocated that performance or results, of
the program or the system, is noticeably degraded."

Sometimes you can't bound resource usage, because you can't bound the
input (unix sort, acting as a filter, for instance, on a system with
no writeable disks). Sometimes, you use so little memory, or allocate
some object once only, or hang around so briefly that you can treat
the OS as a garbage collector -- this is what glibc does, and James's
singleton on its target platform.

It might be a "bug", if one cares to define "bug" in a prescriptive
way; it might be a "memory leak" if one cares to use Microsoft's
definition.

Either way, it's not a program defect, because it does not affect the
correct and efficient behaviour of the program, which is what actually
matters.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,619
Members
45,316
Latest member
naturesElixirCBDGummies

Latest Threads

Top