9

In my threads, I always declare local variables "normally", thus:

procedure TMyThread.Execute ;

var
   i : integer ;

begin
i := 2 ;

etc, If I declare them thus:

procedure TMyThread.Execute ;

threadvar
   j : integer ;

begin
j := 2 ;

how does execution/code generation/speed/thread-safety alter?

menjaraz
  • 7,551
  • 4
  • 41
  • 81
rossmcm
  • 5,493
  • 10
  • 55
  • 118

2 Answers2

19

Well for a start the code with the threadvar is invalid syntax. A threadvar needs to have unit scope rather than local scope.

Local variable

Each invocation (including from different threads, and re-entrant calls) of a function results in different instances of that function's local variables.

Thread local variable

A thread local variable has separate instances for each thread in the process. There is a one-to-one mapping between instances of the variable and threads.

Discussion

If your procedure is not re-entrant, and it is the only procedure that refers to the variable then there will be no semantic difference between a local variable and a threadvar – but if a local variable can be used then it should be.

In terms of performance the threadvar is slower than a local variable and may not even work in the context of a DLL.

My recommendation is to use a local variable wherever it is possible to do so. Use a threadvar (or Thread Local Storage (TLS) when in a DLL) if you need a variable of global scope that has a single instance per thread. However, such need is rare and has the severe downside that thread local variables have many of the same drawbacks as true global variables.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Aha - thanks @David for the syntax pointer. I'm a little hazy on what the syntax should be. I gather I would refer to J as SomeThread.j, but where in the thread do I declare it? I still can't quite see the use of them, though. – rossmcm Mar 03 '11 at 13:05
  • 2
    @ross Don't use them if you don't need to. Stack allocated local variables are the holy grail. If you can do all your work with stack variables then you're golden!! – David Heffernan Mar 03 '11 at 13:07
  • @David I can't think of a place where I would use them – rossmcm Mar 03 '11 at 13:11
  • @ross I do make use of thread local variables sometimes, but it's quite rare and mostly I try to find a way to avoid it because they have many of the bad properties of global variables. – David Heffernan Mar 03 '11 at 13:14
  • @david : a really simple example...? – rossmcm Mar 03 '11 at 13:20
  • @ross I'm going to spend time this afternoon trying to remove them from my code because they are often bad. If there's an example that benefits from thread local I'll post it. – David Heffernan Mar 03 '11 at 13:31
  • 2
    I never noticed until just now, but I can see how the term *thread local variable* can be interpreted as referring to special kind of local variable. I'd hyphenate it — *thread-local variable* — to stress that *thread-local* is modifying *variable*, rather than simply *thread* modifying *local variable*. – Rob Kennedy Mar 03 '11 at 14:55
  • Rossmcm, the syntax for declaring and using threadvars is the same as using any other global variable. When you declare `threadvar J: Integer`, you will refer to it simply as `J` throughout your code. (You'd only say `SomeThread.J` if you have a *unit* named `SomeThread` and you wanted to distinguish between that `J` variable and some other variable declared elsewhere with the same name.) Which value you get when you refer to that variable depends on the current thread context. There's no way to specify which thread's copy you read; it's always "current thread." – Rob Kennedy Mar 03 '11 at 15:00
  • @ross I've studied my codebase and have two situations where I make use of TLS and feel it is justified. The most defensible is a thread-local variable called `UserInterfaceAllowedFromThisThread`. This is easy when my code is built into an .exe but when it's in DLL form, for my Office COM add-in, then it needs extra handling. Because UI is affinitised to a particular thread, then it makes sense for this to be thread-local. – David Heffernan Mar 03 '11 at 16:16
  • @ross The second form of use I have found is for various optimisations to avoid hitting the heap memory manager from the kernel of my computationally intensive code. This multi-threaded, and because I am not using a scalable memory manager, I am allergic to heap allocation in critical areas of the code. I've used TLS to avoid certain heap allocations but it's brittle code and I don't like it. I only put up with it because the alternative is a program that won't scale. The right solution is a scalable memory manager. – David Heffernan Mar 03 '11 at 16:18
2

By using ThreadVar keyword, each thread is given a separate instance of each variable, thereby avoiding data conflicts, and preserving thread independence.

Also you do not need to protect your threadvar variables in critical sections, due to the fact that are local to the thread.

best regards,
Radu

RBA
  • 12,337
  • 16
  • 79
  • 126
  • but surely ordinary local variables declared within the Execute method are separate from other local variables in other threads also. – rossmcm Mar 03 '11 at 13:09
  • @ross yes indeed, locals are always best if they work semantically. What's more they are separate from re-entrant calls to Execute, should that occur. – David Heffernan Mar 03 '11 at 13:10