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:
46
doc/docs.md
46
doc/docs.md
@ -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:
|
||||
|
Reference in New Issue
Block a user