This article will use two examples to practice multithreading programming with pthread, mainly covering two parts:
Parallel computation of the PI value by dividing data
Thread pool development based on the producer-consumer pattern, with the specific business logic simplified to focus on thread management and synchronization
1 Calculating Pi
1.1 Conceptual Overview
Based on the Leibniz formula, calculate a large number of times through multithreading to approximate $\pi$. Use multithreading for dividing data, i.e., each thread handles a part of the data for acceleration.
Due to potential conflicts when multiple threads access a global result, mutexes and semaphores are used to organize threads to orderly add local results to the global outcome.
A task queue is used as a buffer area between the producer and the consumer. Each element in the task queue contains the function to be executed and its parameters, corresponding code is as follows:
On the producer side, the thread_pool_enqueue function is used to add tasks to the task queue. When a producer generates a task, it first protects the task queue with the thread pool’s mutex pool->mutex to prevent multiple threads from modifying the queue simultaneously, then uses the condition variable pool->cond to notify consumers of new tasks.
On the consumer side, the thread_pool_worker function is used to retrieve and execute tasks from the task queue. When a consumer takes a task from the queue, it uses the mutex pool->mutex to protect the task queue. If the task queue is empty, the consumer will be blocked by the condition variable pool->mutex, waiting for the producer to add new tasks to the queue.