Skip to content

Instantly share code, notes, and snippets.

@quonic
Created October 13, 2024 12:08
Show Gist options
  • Save quonic/79cc68afb3fe03425649fa4d2cd1a166 to your computer and use it in GitHub Desktop.
Save quonic/79cc68afb3fe03425649fa4d2cd1a166 to your computer and use it in GitHub Desktop.
A simple custom Odin hello world thread pool example
package main
import "core:fmt"
import "core:thread"
// Array of threads
threads: [dynamic]^thread.Thread
// Pool of data that each thread can access
Pool :: struct {
strings: [dynamic]string,
}
pool: Pool
main :: proc() {
// Initialize our data for the threads
pool.strings = {"Hello", "World", "From", "Odin", "Threads"}
// Create and run our threads
for _, i in pool.strings {
// Create the thread
t, ok := create_thread(proc(t: ^thread.Thread) {
pool := (^Pool)(t.data)
fmt.printfln("Thread %d says: %v", t.user_index, pool.strings[t.user_index])
}, i, &pool).?
// Run the thread if it was created successfully
if ok do run_thread(t)
else if !ok do fmt.printfln("Failed to create thread %d", i)
}
// Wait for all threads to finish
for are_threads_running() {
// Yield the main thread
thread.yield()
}
}
// Thread Management
@(init)
create_thread_pool :: proc() {
// Thanks to VOU-folks for this code: https://github.com/VOU-folks/odin-tcp-server-example/blob/main/main.odin
threads = make([dynamic]^thread.Thread, 0)
thread_cleaner()
}
// Destroy the thread pool
destroy_thread_pool :: proc() {
delete(threads)
}
// Get the number of running threads
get_thread_count :: proc() -> int {
return len(threads)
}
// Check if there are any threads running
are_threads_running :: proc() -> bool {
return get_thread_count() > 0
}
// Create a thread and add it to the pool
create_thread :: proc(
p: proc(_: ^thread.Thread),
id: int,
data: ^Pool = nil,
) -> Maybe(^thread.Thread) {
// Create the thread and check if the thread was created successfully
if t := thread.create(p); t == nil {
// Return nil if the thread was not created
return nil
} else {
// Set the user index and data
t.user_index = id
if data != nil {
t.data = data
}
// Add the thread to the pool
append(&threads, t)
// Return the thread
return t
}
}
// Run a thread
run_thread :: proc(t: ^thread.Thread) {
thread.start(t)
}
// Clean up threads that are done
thread_cleaner :: proc() {
// Create a thread that will clean up the other threads
t := thread.create(
proc(t: ^thread.Thread) {
for {
// Yield the thread to the OS or other threads
thread.yield()
// If there are no threads, continue
if get_thread_count() == 0 {
continue
}
// Check if any threads are done
for i := 0; i < get_thread_count(); {
// Check if the thread is done
if thr := threads[i]; thread.is_done(thr) {
when ODIN_DEBUG {
fmt.printf("Thread %d is done\n", thr.user_index)
}
// Clean up the thread
thr.data = nil
thread.destroy(thr)
ordered_remove(&threads, i)
} else {
// Move to the next thread
i += 1
}
}
}
},
)
// Start the thread cleaner
thread.start(t)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment