Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writable local const

Tags:

delphi

Don't shoot me, but it's the first time I saw a usage of a local writable const (Or maybe I'm just way too senile...): "The WinAPI way (by Peter Below from TeamB)"

Take a look at the local const FullScreen: Boolean = False; and then FullScreen := not FullScreen;

At first I thoght It was a new feature with modern Delphi versions, but it works with my D5 also. So my question is: are local writable constants are exactly the same as declaring a global writable constant?

e.g.

procedure TForm1.Button1Click(Sender: TObject);
Const
  LocalConst: Boolean = False;
begin
  LocalConst := not LocalConst;
  if LocalConst then Beep;
end;

Works the same like this code? :

Const
  GlobalConst_Button2Click: Boolean = False;

procedure TForm1.Button2Click(Sender: TObject);
begin
  GlobalConst_Button2Click := not GlobalConst_Button2Click;
  if GlobalConst_Button2Click then Beep;
end;

Or, LocalConst is local to it's method i.e. static? Is this constant Thread safe?
Can anyone shed some light on this issue?

like image 627
kobik Avatar asked Mar 11 '12 11:03

kobik


1 Answers

The code with the local and global typed constant does exactly the same thing.

As David already stated the global static variable (aka typed constant) is reachable throughout the program and the local static var is not. Below I will refer to typed constants as static variables because that's what they really are.

However the local static variable does persist in memory in exactly the same way as the global static var does. It is just the compiler that does not allow you access to a local var from outside the routine.
Also note that if your local static var is especially large (or you have very many of them) they will eat up a constant chunk of memory (even though I cannot conceive of a scenario where this could be a problem).

Because the static variable resides in a fixed location it is not thread safe. It effectively turns into a shared variable between all thread instances.
If the static var cannot be altered in a single CPU cycle (i.e. if it's bigger than an integer or if it's a complex type) than two threads can alter different parts of the variable at the same time, often leading to corruption.

It it can be altered in a single cycle, e.g. a boolean or integer than you can never know whether the thread you are in is the one that changed it last or another one did which will lead to unpredictable results in most cases.

In short
Using static vars in threaded code is a very bad idea unless you know exactly what you're doing.

An exception to this might be an integer counter where you only increment and test to see if more than x executions have occurred.
Static vars generally unsuitable for passing messages between threads.

If you want to share data between threads it's a better idea to use threadvar,
see: http://en.wikipedia.org/wiki/Thread-local_storage
and: https://stackoverflow.com/search?q=delphi+threadvar

Finally
There are very few problems that require global static vars and they are best avoided because they are dangerous.
Local static vars are useful in single threaded code to keep track of state between different executions of a routine.
They are useless for doing this in multi-threaded code because of race conditions.

like image 152
Johan Avatar answered Nov 15 '22 19:11

Johan