Temporary varriables and thread safety

C

Chad Zalkin

We are evaluating some old code that was written as part of our math
library.
This code uses some optimizations that I'm not sure are necessary or
safe, but is a source of debate between my coworkers.

Method 1 includes a temporary storage varriable at class scope.
Method 2 includes a temporary storage varriable at method scope.
Method 3 includes a temporary static storage varriable at method scope.

Are any of the methods better than the others in terms of speed and
thread safety?
I don't believe method 1 or 3 are thread safe, but I think method 2 may
be too slow for a high-performance library. Is there a method 4 that
we should evaluate?

As an aside, I can't find in the standard where static is addressed in
terms of a member function. Is it true that a static varriable within
a member function exists for all instances?



/// ---- method 1

class vector {
....
private:
vector tempVector;
};


vector::somefunction() {
// writes to tempVector as temporary storage
}


/// ---- method 2
class vector {
....
};


vector::somefunction() {
vector tempVector;
// writes to tempVector as temporary storage
}



/// --- method 3
class vector {
....
};


vector::somefunction() {
static vector tempVector;
// writes to tempVector as temporary storage
}
 
V

Victor Bazarov

Chad said:
We are evaluating some old code that was written as part of our math
library.
This code uses some optimizations that I'm not sure are necessary or
safe, but is a source of debate between my coworkers.

Method 1 includes a temporary storage varriable at class scope.
Method 2 includes a temporary storage varriable at method scope.
Method 3 includes a temporary static storage varriable at method scope.

Are any of the methods better than the others in terms of speed and
thread safety?

This question is _better_ asked in a newsgroup that actually deals with
threading: comp.programming.threads. C++ does not have support, not does
it have any definitions of, threading. The program is assumed to be
single-threaded in C++ standard.

Now, when talking about threads it is essential to identify the data that
can be changed. You didn't say how many threads are accessing what part
of data at some point.
I don't believe method 1 or 3 are thread safe, but I think method 2 may
be too slow for a high-performance library. Is there a method 4 that
we should evaluate?

As an aside, I can't find in the standard where static is addressed in
terms of a member function. Is it true that a static varriable within
a member function exists for all instances?

A static object is a static object regardless of what scope it's in. It's
essentially a singleton.
/// ---- method 1

class vector {
...
private:
vector tempVector;

You simply _physically_ cannot have an object that contains an instance of
its own type.
};


vector::somefunction() {

Does this one have any return value type?
// writes to tempVector as temporary storage

It is generally _unknown_ here what storage duration 'tempVector' has,
since its storage duration is the same as that of '*this' object. (All
that assuming that the type of 'tempVector' is _not_ the same as the
object that contains it)
}


/// ---- method 2
class vector {
...
};


vector::somefunction() {
vector tempVector;
// writes to tempVector as temporary storage

This is the most "thread-safe", largely because in many threading models
(if not all), automatic variables are "per-thread".
}



/// --- method 3
class vector {
...
};


vector::somefunction() {
static vector tempVector;
// writes to tempVector as temporary storage

This is the _least_ "thread-safe", since static objects are usually shared
between all threads.

To sum up: method 2 is generally thread-safe, method 3 is generally not,
and nothing can be said about method 1.


V
 
B

Ben Pope

Chad said:
We are evaluating some old code that was written as part of our math
library.
This code uses some optimizations that I'm not sure are necessary or
safe, but is a source of debate between my coworkers.

Method 1 includes a temporary storage varriable at class scope.
Method 2 includes a temporary storage varriable at method scope.
Method 3 includes a temporary static storage varriable at method scope.

Are any of the methods better than the others in terms of speed and
thread safety?
I don't believe method 1 or 3 are thread safe, but I think method 2 may
be too slow for a high-performance library. Is there a method 4 that
we should evaluate?

What makes you think that accessing a variable at local scope is slower
than that at class scope?

The narrower the scope the easier it is for the compiler to optimise.

If there is no requirement for the temporary variable to have scope
outside of a function, don't do it. Declare objects as late as
possible, and with the narrowest scope possible.

Be sure to use initialisation rather than assignment wherever possible.
If the object has a constructor, use an initialisation list. When
instantiating the object, use initialisation rather than default
construction and assignment.

You haven't really described how this temporary object is actually
initialised, how it is used, and why you think it is an optimisation
technique.

I mean, what is the alternative that you suppose is slower?

Ben Pope
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

Victor said:
You simply _physically_ cannot have an object that contains an instance of
its own type.

Yes, but one could use a pointer for tempVector.
If the class vector contains other dynamically allocated members,
this might be a performance improvement over method 2
(assuming that each thread maintains its own instance of vector).

Stephan
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

Chad said:
We are evaluating some old code that was written as part of our math
library.
This code uses some optimizations that I'm not sure are necessary or
safe, but is a source of debate between my coworkers.

Method 1 includes a temporary storage varriable at class scope.
Method 2 includes a temporary storage varriable at method scope.
Method 3 includes a temporary static storage varriable at method scope.

Are any of the methods better than the others in terms of speed and
thread safety?
I don't believe method 1 or 3 are thread safe, but I think method 2 may
be too slow for a high-performance library. Is there a method 4 that
we should evaluate?

In theory you might require that the thread provides the temp. vector
(in analogy to localtime, localtime_r)

vector::somefunction(vector& tempVector);

However this will only be useful if the tempory vector is used outside
the class vector and not an implementation detail of
vector::somefunction().

Regards, Stephan
(e-mail address removed)
Open source rating and billing engine for communication networks.
 
C

Chad Zalkin

Victor said:
This question is _better_ asked in a newsgroup that actually deals with
threading: comp.programming.threads. C++ does not have support, not does
it have any definitions of, threading. The program is assumed to be
single-threaded in C++ standard.

Now, when talking about threads it is essential to identify the data that
can be changed. You didn't say how many threads are accessing what part
of data at some point.


A static object is a static object regardless of what scope it's in. It's
essentially a singleton.


You simply _physically_ cannot have an object that contains an instance of
its own type.


Does this one have any return value type?


It is generally _unknown_ here what storage duration 'tempVector' has,
since its storage duration is the same as that of '*this' object. (All
that assuming that the type of 'tempVector' is _not_ the same as the
object that contains it)


This is the most "thread-safe", largely because in many threading models
(if not all), automatic variables are "per-thread".


This is the _least_ "thread-safe", since static objects are usually shared
between all threads.


To sum up: method 2 is generally thread-safe, method 3 is generally not,
and nothing can be said about method 1.


V


In defence of my own sanity, method 1 was not meant to include itself.
Let's all imagine that the tempVector is now of type foo in all
methods.

The part that I forgot to mention in my haste was that more than one
method will use the temporary storage:


class vector {
void add(); // needs temporary storage
void sub(); // needs temporary storage
void dot(); // needs temporary storage
};

class tempStorage
{
public:
// some data members
};

Now, let's ignore the threadding issue since it is OT.

If add(), sub(), and dot() all need to store some temporary data during
their runtime,
is it more efficient to store this data at class level (constructing
and destructing once per object) or at function level (constructing and
destructing once per function call; potentially many more times).

Since add(), sub(), and dot() do not call each other, storing the data
at class level becomes possible. (But then the thread issue comes into
play...)

What are the pro's and con's of scoping at each level? What can I
trust the compiler to be allowed to optimize? What can I do to help
the compiler optimize?


Thanks for any insight!
 
V

Victor Bazarov

Chad said:
[..]
Let's all imagine that the tempVector is now of type foo in all
methods.

The part that I forgot to mention in my haste was that more than one
method will use the temporary storage:


class vector {
void add(); // needs temporary storage
void sub(); // needs temporary storage
void dot(); // needs temporary storage
};

class tempStorage
{
public:
// some data members
};

Now, let's ignore the threadding issue since it is OT.

If add(), sub(), and dot() all need to store some temporary data during
their runtime,
is it more efficient to store this data at class level (constructing
and destructing once per object) or at function level (constructing and
destructing once per function call; potentially many more times).

<triallawyer>
Objection: leading!
</triallawyer>

It all depends on how much it takes to construct that object and how big
it actually is. You are forgetting an important element of performance:
make your objects smaller. If you store anything at the object level, you
make it bigger. It may not have effect on the performance in this
particular area of your program, but somewhere else... Which leads me to
another point: do not attempt to optimize before you have a chance to
measure the performance and conclude _whether_ and _where_ the actual
optimization is needed.
Since add(), sub(), and dot() do not call each other, storing the data
at class level becomes possible. (But then the thread issue comes into
play...)

What are the pro's and con's of scoping at each level? What can I
trust the compiler to be allowed to optimize? What can I do to help
the compiler optimize?

Two rules are at play here, I believe. (1) The tighter the scope the
easier it is to optimize and maintain, and (2) Premature optimization is
the root of all evil.

V
 
B

Ben Pope

Chad said:
In defence of my own sanity, method 1 was not meant to include itself.
Let's all imagine that the tempVector is now of type foo in all
methods.

The part that I forgot to mention in my haste was that more than one
method will use the temporary storage:


class vector {
void add(); // needs temporary storage
void sub(); // needs temporary storage
void dot(); // needs temporary storage
};

class tempStorage
{
public:
// some data members
};

Now, let's ignore the threadding issue since it is OT.

If add(), sub(), and dot() all need to store some temporary data during
their runtime,
is it more efficient to store this data at class level (constructing
and destructing once per object) or at function level (constructing and
destructing once per function call; potentially many more times).

Well, you forgot something:

Class level: Contruction once. Assignment for each function call.
Function level: Construct & initialisation once per call.
Since add(), sub(), and dot() do not call each other, storing the data
at class level becomes possible. (But then the thread issue comes into
play...)

Indeed. And although you don't need to construct the object, you do
need to assign to it, which may or may not be faster than constructing
and initialising.

Don't forget that it's in automatic storage, not heap... so the memory
is already "allocated".
What are the pro's and con's of scoping at each level? What can I
trust the compiler to be allowed to optimize? What can I do to help
the compiler optimize?

As I said, declare variables as late as possible and in as narrow scope
as possible, prefer initialisation to assignment.

Not only do you help the compiler optimise, by narrowing what it has to
look at, but you also fix thread issues.

The only way you'll know if this works in your situation is by profiling.

Ben Pope
 

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

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,145
Latest member
web3PRAgeency
Top