- I feel an example coming on.
Let's go into the project,
and have a look at the demo static mutable.
So here we are,
let's go into demo_static_mutable.
And in here I've imported the atomic I32
and the order in enum.
And I've declared a global counter.
So that's thread safe.
And because it's using atomic I32,
I've got a global counter whose initial value is zero.
And then I've got a couple of functions here.
I've got an unsafe function, which has a local counter.
I've got a global counter.
And I've got a local counter, just for this function,
which is mutable.
And I've just got a normal stack-based variable X.
When I try to increment my local counter,
that's just a regular int 32, that's not thread safe.
The only way I can get away with incrementing that static
is because I've declared my function as unsafe.
I also increment the global counter.
Well, that would've been safe anyway
because my global counter is atomic.
So it is implicitly thread safe outta the box.
So I've got a unsafe increment of my local static,
my local stack-based variable, and my global static.
And I output the values of the local count,
my local variable, and my global count, here.
I call that function twice.
Okay, just to see these values change.
And then F2 is a function down here,
let's have a look at F2.
So in F2, in the first function, I used a regular integer.
And when I tried to change it,
that wasn't thread safe, hence the unsafe cue,
oh by the way, did you notice that when I call F1, up here,
from my kind of entry point code, I had to make it unsafe,
in order to call F1.
But F2 is safe, I can just call that function normally,
because in F2 I've been quite careful.
I've declared a static local counter.
This is local to this function, initially zero.
And I incremented in a thread safe kind of way.
I also increment the global counter
in a thread safe kind of way.
And then I output the values.
Let's run the code, or first of all,
let me remember to call that function, from main,
I'm going to call demo static mutable.
Okay, so let's run the code,
and then I'll just run through the statements one more time,
so you can kinda see what's actually been output.
So cargo run.
Cargo run.
And I'm gonna walk you through the code in here.
Right then, so in demo static mutable, here we are.
I call F1, the first time.
And the local counter is zero.
Okay, so that kind of makes sense.
I then increment it to one.
So the local counter is now one, my X is one,
and my global counter is also incremented,
my global counter was zero initially.
There it is.
So let's see what I've done.
I've incremented my local counter.
I've incremented my stack-based variable,
and I've implemented the global counter.
So the local counter is now one, X is one,
and the global counter is also one.
At the end of this function, my local counter is static,
so it is preserved.
My stack-based X is popped off the stack and is gone.
So when I call the function F1 the next time,
then the value of the local counter will still be one,
X will be recreated as zero.
So when I increment my local counter,
my local counter is now two, for this function.
X was recreated from scratch,
because it wasn't static, it was stack-based storage,
so that was back to zero, incremented to one.
My global counter.
The one right at the top is now two as well.
Right, let's see what happens when we call F2.
So in F2, it has its own local counter.
This local counter here is obviously a different one
to the one that we declared in F1.
F1 had its local counter,
and F2 has its own local counter,
so that will be initialized to zero, initially.
And this local X will be zero.
Increment my local counter.
So my local counter here will now be incremented to one.
X will be incremented to one.
My global counter, that's the global counter
right at the top, that's going to be three now.
So, local count is one.
That's correct, that was incremented to one.
My local X is one,
my global counter is retained across all functions,
that's now three.
And then finally, I call my F2 function a second time.
Okay?
So the local counter here is still the value that it was,
it was one.
This variable gets recreated.
Increment my local counter to two.
Increment my local variable to one,
increment the global counter to four.
Okay, so my local count is two.
My local count just for this function
is incremented and preserved, and now it's two.
And my local X gets kinda created and recreated every time,
so that's just one, back to one again.
And my global counter is four.
Okay, so, hopefully that all makes sense.
The main point to take out of this
is that when you have statics,
static variables are not the norm,
it's just taking us a while to explain them,
because they're quite tricky.
But when you do have statics,
the main issue is thread safety.
Because the function can be called on multiple threads.
Multiple threads could access the static.
So whenever you try to change
or, you know, reassign the value to a static,
thread safety is important, you either use mutexes,
if you have a general data type,
or you can use these atomics
if you're dealing with primitives.