# Multi-threading Cross-platform threading primitives and synchronization mechanisms for concurrent programming. ## Thread Pool Operations Use `ThreadPoolLite::Queue` and `ThreadPoolLite::QueueLambda` for thread pool execution. Use static functions `ThreadPoolLite::Queue` or `ThreadPoolLite::QueueLambda` to run a function in another thread. Use `TaskQueue` when work must be queued from multiple threads but executed by one blocking task loop. ### ThreadPoolLite Benefits The thread pool provides several advantages over manual thread creation: - Automatic thread lifecycle management - Resource pooling to avoid thread creation overhead - Better system resource utilization - Simplified concurrent programming model ### Usage Examples ```cpp // Queue a function pointer ThreadPoolLite::Queue(someFunction); // Queue a lambda expression ThreadPoolLite::QueueLambda([]() { // Work to be done in background thread }); ``` ## Task Queue Operations `TaskQueue` owns a FIFO task list and a semaphore-backed blocking loop. Call `QueueTask` from any thread, run `RunTaskQueue` on the thread that should execute the work, and call `QueueExitTask` to leave the loop after already queued tasks are complete. ```cpp auto queue = Ptr(new TaskQueue); auto thread = Ptr(Thread::CreateAndStart([=]() { queue->RunTaskQueue(); }, false)); queue->QueueTask([]() { // Runs on the task queue thread }); queue->QueueExitTask(); ``` Use `TaskQueue` instead of `ThreadPoolLite` when the order and single-threaded execution context of tasks matters. ## Thread Control Operations ### Thread Pausing Use `Thread::Sleep` for thread pausing. Use static function `Thread::Sleep` to pause the current thread for some milliseconds. ### Thread Identification Use `Thread::GetCurrentThreadId` for thread identification. Use static function `Thread::GetCurrentThreadId` to get an identifier for the OS native thread running the current function. ## Manual Thread Creation Use `Thread::CreateAndStart` only when thread pool is insufficient. `Thread::CreateAndStart` could be used to run a function in another thread while returning a `Thread*` to control it, but this is not recommended. Always use `ThreadPoolLite` if possible. Use `TaskQueue` when a long-lived single-threaded task loop is required. ### When to Use Manual Threads Manual thread creation should only be considered when: - You need fine-grained control over thread lifecycle - Thread-specific configurations are required - The thread pool doesn't meet specific timing requirements - Working with legacy code that requires direct thread handles ## Thread Pool with Synchronization A `ThreadPoolLite` call with an `EventObject` is a better version of `Thread::Wait`. `TaskQueue` is the alternative when multiple callers should enqueue work to one owner thread. This approach provides better resource management and avoids the complexities of manual thread synchronization. ## Extra Content ### Threading Best Practices 1. **Prefer Thread Pool**: Use `ThreadPoolLite` for most concurrent operations, and use `TaskQueue` for serialized owner-thread work 2. **Avoid Thread Creation**: Manual thread creation adds overhead and complexity 3. **Use Synchronization Primitives**: Combine threading with proper synchronization objects 4. **Handle Exceptions**: Ensure proper exception handling in threaded code ### Performance Considerations - **Thread Pool**: Minimal overhead for task scheduling and execution - **Thread Creation**: Significant overhead for creating and destroying threads - **Context Switching**: Consider the cost of frequent context switches - **Resource Contention**: Be aware of shared resource access patterns ### Cross-Platform Considerations The threading API provides a unified interface across platforms: - Windows: Uses Windows thread API internally - Linux: Uses pthread API internally - Behavior remains consistent across platforms - Thread IDs are platform-specific but the API is uniform ### Memory Management - Thread pool automatically manages worker threads - Manual threads require explicit cleanup - Lambda captures should be carefully managed for thread safety - Avoid capturing references to stack variables in threaded lambdas ### Error Handling Threading operations can fail due to: - System resource exhaustion - Permission restrictions - Platform-specific limitations Always check return values and handle potential failures gracefully. ### Integration with Synchronization Multi-threading works best when combined with appropriate synchronization primitives: - Use with `Mutex` for cross-process synchronization - Combine with `CriticalSection` for in-process protection - Integrate with `EventObject` for thread coordination - Apply `ConditionVariable` for complex waiting scenarios