在当今的多核处理器时代,并发编程已经成为提高程序性能的关键技术。C语言作为一种底层编程语言,提供了丰富的并发编程工具。本文将深入探讨C语言中的线程池与回调函数,旨在帮助读者掌握高效并发编程的实践技巧。
线程池:并发编程的基石
线程池是一种常用的并发编程模型,它通过复用一定数量的线程来执行任务,从而减少线程创建和销毁的开销。在C语言中,我们可以使用POSIX线程(pthread)库来实现线程池。
1. 线程池的基本原理
线程池的基本原理是:创建一定数量的线程,并将这些线程放入线程池中。当有任务需要执行时,将任务提交给线程池,线程池中的线程会按照一定的策略(如先进先出、优先级等)执行任务。
2. 线程池的实现
以下是一个简单的线程池实现示例:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define THREAD_POOL_SIZE 4
typedef struct {
void (*func)(void*);
void *arg;
} Task;
typedef struct {
pthread_t *threads;
Task *tasks;
int task_count;
int capacity;
pthread_mutex_t lock;
pthread_cond_t cond;
int shutdown;
} ThreadPool;
void *thread_routine(void *arg) {
ThreadPool *pool = (ThreadPool *)arg;
while (1) {
pthread_mutex_lock(&pool->lock);
while (pool->task_count == 0 && !pool->shutdown) {
pthread_cond_wait(&pool->cond, &pool->lock);
}
if (pool->shutdown && pool->task_count == 0) {
pthread_mutex_unlock(&pool->lock);
break;
}
Task task = pool->tasks[0];
pool->task_count--;
pthread_mutex_unlock(&pool->lock);
task.func(task.arg);
}
return NULL;
}
ThreadPool *create_thread_pool() {
ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * THREAD_POOL_SIZE);
pool->tasks = (Task *)malloc(sizeof(Task) * THREAD_POOL_SIZE);
pool->task_count = 0;
pool->capacity = THREAD_POOL_SIZE;
pthread_mutex_init(&pool->lock, NULL);
pthread_cond_init(&pool->cond, NULL);
pool->shutdown = 0;
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&pool->threads[i], NULL, thread_routine, pool);
}
return pool;
}
void destroy_thread_pool(ThreadPool *pool) {
pthread_mutex_lock(&pool->lock);
pool->shutdown = 1;
pthread_cond_broadcast(&pool->cond);
pthread_mutex_unlock(&pool->lock);
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_join(pool->threads[i], NULL);
}
pthread_mutex_destroy(&pool->lock);
pthread_cond_destroy(&pool->cond);
free(pool->threads);
free(pool->tasks);
free(pool);
}
void submit_task(ThreadPool *pool, void (*func)(void*), void *arg) {
pthread_mutex_lock(&pool->lock);
if (pool->task_count >= pool->capacity) {
pthread_mutex_unlock(&pool->lock);
return;
}
pool->tasks[pool->task_count].func = func;
pool->tasks[pool->task_count].arg = arg;
pool->task_count++;
pthread_cond_signal(&pool->cond);
pthread_mutex_unlock(&pool->lock);
}
void task_example(void *arg) {
printf("Task executed by thread %ld\n", pthread_self());
}
int main() {
ThreadPool *pool = create_thread_pool();
for (int i = 0; i < 10; i++) {
submit_task(pool, task_example, NULL);
}
destroy_thread_pool(pool);
return 0;
}
3. 线程池的应用场景
线程池适用于以下场景:
- 需要处理大量并发任务,且任务执行时间较短;
- 任务之间相互独立,无依赖关系;
- 线程创建和销毁开销较大。
回调函数:异步编程的关键
回调函数是一种常见的异步编程模式,它允许我们将任务提交给另一个函数执行,并在任务完成后通知我们。在C语言中,我们可以通过定义函数指针来实现回调函数。
1. 回调函数的基本原理
回调函数的基本原理是:定义一个函数指针,将其传递给另一个函数,并在适当的时候调用该函数。
2. 回调函数的实现
以下是一个简单的回调函数实现示例:
#include <stdio.h>
void process_data(int data, void (*callback)(int)) {
// 处理数据
printf("Processing data: %d\n", data);
// 调用回调函数
callback(data);
}
void data_processed(int data) {
printf("Data processed: %d\n", data);
}
int main() {
process_data(10, data_processed);
return 0;
}
3. 回调函数的应用场景
回调函数适用于以下场景:
- 异步编程,如网络请求、文件读写等;
- 事件驱动编程,如GUI编程、游戏开发等;
- 需要将任务分解为多个步骤,并在每个步骤完成后执行回调函数。
总结
线程池与回调函数是C语言并发编程中常用的技术。通过掌握这两种技术,我们可以提高程序的并发性能,实现高效编程。在实际应用中,我们需要根据具体场景选择合适的并发编程模型,并合理使用线程池与回调函数。
