Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

@@ -0,0 +1,2 @@
*.c
*.out
@@ -0,0 +1,44 @@
/*
This code demonstrates thread safety using atomic operations in V.
Thread safety is achieved by using atomic functions to manipulate the shared counter variable.
Atomic operations ensure that the read-modify-write sequence is performed as a single, indivisible operation,
preventing race conditions and ensuring data integrity when accessed by multiple threads concurrently.
Key points:
1. **Atomic Fetch and Add**: The `C.atomic_fetch_add_u32` function atomically increments the counter.
This means that the increment operation is performed without interruption, ensuring that no two threads
can increment the counter simultaneously and cause a race condition.
2. **Atomic Load**: The `C.atomic_load_u32` function atomically reads the value of the counter.
This ensures that the read operation is consistent and not affected by concurrent writes from other threads.
3. **Thread Synchronization**: The `spawn` function is used to create new threads that run the `increment` function.
The `wait` method is called on each thread to ensure that the main thread waits for both threads to complete
before reading the final value of the counter.
By using atomic operations and proper thread synchronization, the code ensures that the shared counter is
incremented safely and correctly by multiple threads.
*/
import sync as _
// Function to increment the atomic counter
fn increment(atomic_counter &u32) {
C.atomic_fetch_add_u32(atomic_counter, 1)
}
fn main() {
atomic_counter := u32(0) // Atomic counter variable
// Spawn two threads that increment the atomic counter
t1 := spawn increment(&atomic_counter)
t2 := spawn increment(&atomic_counter)
// Wait for both threads to complete
t1.wait()
t2.wait()
// Load and print the final value of the atomic counter
final_count := C.atomic_load_u32(&atomic_counter)
println('Atomic Counter: ${final_count}')
}
@@ -0,0 +1,36 @@
/*
This example demonstrates thread safety using V's concurrency features.
Key points:
- The `SharedData` struct contains a mutable counter that will be accessed by multiple threads.
- The `increment` function increments the counter within a lock to ensure that only one thread
can modify the counter at a time, preventing race conditions.
- In the `main` function, two threads are spawned to increment the shared counter concurrently.
- The `lock` keyword is used to ensure exclusive access to the shared data during modification,
and the `rlock` keyword is used to allow multiple threads to read the data concurrently without
modification.
This ensures that the counter is incremented safely and the final value is printed correctly.
*/
struct SharedData {
mut:
counter int
}
fn increment(shared data SharedData) {
lock data {
data.counter++
}
}
fn main() {
shared data := SharedData{}
threads := [spawn increment(shared data), spawn increment(shared data)]
for t in threads {
t.wait() // Wait for both threads to complete
}
rlock data {
println('Counter: ${data.counter}')
}
}
+94
View File
@@ -0,0 +1,94 @@
/*
This example demonstrates thread safety using a queue of callbacks.
### Functions:
- `producer`: creates a callback and adds it to the queue.
- `consumer`: consumes a callback from the queue and runs it.
- `heavy_processing`: a heavy processing function that is added to the queue.
### Thread Safety:
- The `fn producer` function is protected by a mutex. It locks the mutex before adding a callback
to the queue and unlocks it after adding the callback.
- The `fn consumer` function is also protected by the same mutex. It locks the mutex before
consuming a callback from the queue and unlocks it after consuming the callback.
- The `heavy_processing` function is added to the queue by the main thread before the producer
threads start producing callbacks. The main thread is the only thread that adds this function to
the queue, so it doesn't need to be protected by a mutex.
*/
import time
import sync
type Callback = fn (id string)
fn producer(producer_name string, mut arr []Callback, mut mtx sync.Mutex) {
for i in 1 .. 5 {
mtx.lock()
arr << fn [producer_name, i] (consumer_name string) {
println('task ${i} created by producer ${producer_name}: consumed by ${consumer_name}')
time.sleep(500 * time.millisecond)
}
println('Produced: ${i}')
time.sleep(50 * time.millisecond)
mtx.unlock()
}
}
fn consumer(consumer_name string, mut arr []Callback, mut mtx sync.Mutex) {
for {
mtx.lock()
if arr.len > 0 {
callback := arr[0]
arr.delete(0)
mtx.unlock()
callback(consumer_name) // run after unlocking to allow other threads to consume
continue
} else {
println('- No items to consume')
mtx.unlock()
// time.sleep(500 * time.millisecond)
// continue // uncomment to run forever
break // uncomment to stop after consuming all items
}
}
}
fn heavy_processing(queue_id string) {
println('One more: ${queue_id}')
time.sleep(500 * time.millisecond)
}
fn main() {
mut mtx := sync.new_mutex()
mut arr := []Callback{}
producer_threads := [
spawn producer('Paula', mut &arr, mut mtx),
spawn producer('Adriano', mut &arr, mut mtx),
spawn producer('Kaka', mut &arr, mut mtx),
spawn producer('Hitalo', mut &arr, mut mtx),
spawn producer('Jonh', mut &arr, mut mtx),
]
mut consumer_threads := [
spawn consumer('consumer number 0', mut &arr, mut mtx),
]
// spawn 16 consumers
for i in 1 .. 16 {
consumer_threads << spawn consumer('consumer number ${i}', mut &arr, mut mtx)
}
mtx.lock()
arr << heavy_processing
mtx.unlock()
for t in producer_threads {
t.wait()
}
for t in consumer_threads {
t.wait()
}
}
+16
View File
@@ -0,0 +1,16 @@
### Run
```sh
v -prod -gc none -cc gcc ./queue.v && \
./queue
```
### Valgrind
```sh
# Helgrind: a tool for detecting synchronisation errors in programs that use the POSIX pthreads threading primitives.
valgrind --tool=helgrind ./queue
# DRD: a tool for detecting errors in multithreaded programs. The tool works for any program that uses the POSIX threading primitives or that uses threading concepts built on top of the POSIX threading primitives.
valgrind --tool=drd ./queue
```