1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

all: more improvements for global variables (#10986)

This commit is contained in:
Uwe Krüger
2021-07-29 09:57:31 +02:00
committed by GitHub
parent 7547882c11
commit 08aa6c08f6
7 changed files with 168 additions and 13 deletions

View File

@ -132,6 +132,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
* [sizeof and __offsetof](#sizeof-and-__offsetof)
* [Calling C from V](#calling-c-from-v)
* [Atomics](#atomics)
* [Global Variables](#global-variables)
* [Debugging](#debugging)
* [Conditional compilation](#conditional-compilation)
* [Compile time pseudo variables](#compile-time-pseudo-variables)
@ -4297,6 +4298,7 @@ fn C.atomic_compare_exchange_strong_u32(&u32, &u32, u32) bool
const num_iterations = 10000000
// see section "Global Variables" below
__global (
atom u32 // ordinary variable but used as atomic
)
@ -4354,6 +4356,50 @@ It is not predictable how many replacements occur in which thread, but the sum w
be 10000000. (With the non-atomic commands from the comments the value will be higher or the program
will hang – dependent on the compiler optimization used.)
## Global Variables
By default V does not allow global variables. However, in low level applications they have their
place so their usage can be enabled with the compiler flag `-enable-globals`.
Declarations of global variables must be surrounded with a `__global ( ... )`
specification – as in the example [above](#atomics).
An initializer for global variables must be explicitly converted to the
desired target type. If no initializer is given a default initialization is done.
Some objects like semaphores and mutexes require an explicit initialization *in place*, i.e.
not with a value returned from a function call but with a method call by reference.
A separate `init()` function can be used for this purpose – it will be called before `main()`:
```v globals
import sync
__global (
sem sync.Semaphore // needs initialization in `init()`
mtx sync.RwMutex // needs initialization in `init()`
f1 = f64(34.0625) // explicily initialized
shmap shared map[string]f64 // initialized as empty `shared` map
f2 f64 // initialized to `0.0`
)
fn init() {
sem.init(0)
mtx.init()
}
```
Be aware that in multi threaded applications the access to global variables is subject
to race conditions. There are several approaches to deal with these:
- use `shared` types for the variable declarations and use `lock` blocks for access.
This is most appropriate for larger objects like structs, arrays or maps.
- handle primitive data types as "atomics" using special C-functions (see [above](#atomics)).
- use explicit synchronization primitives like mutexes to control access. The compiler
cannot really help in this case, so you have to know what you are doing.
- don't care – this approach is possible but makes only sense if the exact values
of global variables do not really matter. An example can be found in the `rand` module
where global variables are used to generate (non cryptographic) pseudo random numbers.
In this case data races lead to random numbers in different threads becoming somewhat
correlated, which is acceptable considering the performance penalty that using
synchonization primitives would represent.
### Passing C compilation flags
Add `#flag` directives to the top of your V files to provide C compilation flags like: