C语言-单例模式实现线程池
Posted Michael_Good
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言-单例模式实现线程池相关的知识,希望对你有一定的参考价值。
C语言单例模式实现线程池。
该代码中,使用了单例模式来创建线程池对象,保证了整个程序中只有一个线程池对象。
线程池中包含了任务队列、工作线程数组、互斥锁、条件变量等成员,通过这些成员来实现任务的提交和执行。
在主函数中,提交了10个任务,每个任务都是一个简单的打印数字的函数,最后等待所有任务执行完毕后销毁线程池。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_POOL_SIZE 5
// 任务结构体
typedef struct
void (*task)(void*);
void* arg;
Task;
// 线程池结构体
typedef struct
Task* tasks; // 任务队列
int size; // 任务队列大小
int head; // 任务队列头指针
int tail; // 任务队列尾指针
int count; // 任务队列中任务数量
pthread_mutex_t lock; // 互斥锁
pthread_cond_t not_empty; // 非空条件变量
pthread_cond_t not_full; // 非满条件变量
int shutdown; // 线程池是否关闭
pthread_t* threads; // 工作线程数组
int thread_count; // 工作线程数量
ThreadPool;
// 线程池单例结构体
typedef struct
ThreadPool* pool; // 线程池指针
ThreadPoolSingleton;
static ThreadPoolSingleton* instance = NULL; // 线程池单例对象指针
// 工作线程函数
void* worker(void* arg)
ThreadPool* pool = (ThreadPool*)arg;
while (1)
pthread_mutex_lock(&pool->lock);
while (pool->count == 0 && !pool->shutdown)
pthread_cond_wait(&pool->not_empty, &pool->lock);
if (pool->count == 0 && pool->shutdown)
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL);
Task task = pool->tasks[pool->head];
pool->head = (pool->head + 1) % pool->size;
pool->count--;
pthread_cond_signal(&pool->not_full);
pthread_mutex_unlock(&pool->lock);
task.task(task.arg);
return NULL;
// 创建线程池函数
ThreadPool* create_thread_pool(int thread_count, int queue_size)
ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));
pool->tasks = (Task*)malloc(sizeof(Task) * queue_size);
pool->size = queue_size;
pool->head = 0;
pool->tail = 0;
pool->count = 0;
pthread_mutex_init(&pool->lock, NULL);
pthread_cond_init(&pool->not_empty, NULL);
pthread_cond_init(&pool->not_full, NULL);
pool->shutdown = 0;
pool->threads = (pthread_t*)malloc(sizeof(pthread_t) * thread_count);
pool->thread_count = thread_count;
for (int i = 0; i < thread_count; i++)
pthread_create(&pool->threads[i], NULL, worker, pool);
return pool;
// 销毁线程池函数
void destroy_thread_pool(ThreadPool* pool)
pthread_mutex_lock(&pool->lock);
pool->shutdown = 1;
pthread_mutex_unlock(&pool->lock);
pthread_cond_broadcast(&pool->not_empty);
for (int i = 0; i < pool->thread_count; i++)
pthread_join(pool->threads[i], NULL);
free(pool->threads);
free(pool->tasks);
pthread_mutex_destroy(&pool->lock);
pthread_cond_destroy(&pool->not_empty);
pthread_cond_destroy(&pool->not_full);
free(pool);
// 提交任务函数
void submit_task(ThreadPool* pool, void (*task)(void*), void* arg)
pthread_mutex_lock(&pool->lock);
while (pool->count == pool->size && !pool->shutdown)
pthread_cond_wait(&pool->not_full, &pool->lock);
if (pool->shutdown)
pthread_mutex_unlock(&pool->lock);
return;
pool->tasks[pool->tail].task = task;
pool->tasks[pool->tail].arg = arg;
pool->tail = (pool->tail + 1) % pool->size;
pool->count++;
pthread_cond_signal(&pool->not_empty);
pthread_mutex_unlock(&pool->lock);
// 任务函数
void task_func(void* arg)
int* num = (int*)arg;
printf("task %d is running\\n", *num);
free(num);
// 任务包装函数
void* task_wrapper(void* arg)
TaskWrapper* wrapper = (TaskWrapper*)arg;
submit_task(wrapper->pool, wrapper->task, wrapper->arg);
free(wrapper);
return NULL;
init_instance()
instance = (ThreadPoolSingleton*)malloc(sizeof(ThreadPoolSingleton));
instance->pool = create_thread_pool(THREAD_POOL_SIZE, THREAD_POOL_SIZE);
// 获取线程池单例对象函数
ThreadPool* get_thread_pool_instance()
return instance->pool;
int main()
init_instance(); /* 程序一开始,就必须执行。不然,与懒汉式无较大差异 */
ThreadPool* pool = get_thread_pool_instance(); // 获取线程池单例对象
for (int i = 0; i < 10; i++)
int* num = (int*)malloc(sizeof(int));
*num = i;
TaskWrapper* wrapper = (TaskWrapper*)malloc(sizeof(TaskWrapper));
wrapper->pool = pool
wrapper->task = task_func;
wrapper->arg = num;
pthread_t tid;
pthread_create(&tid, NULL, task_wrapper, wrapper); // 提交任务
sleep(1); // 等待所有任务执行完毕
destroy_thread_pool(pool); // 销毁线程池
return 0;
/*
该示例代码中,使用了单例模式来创建线程池对象,保证了整个程序中只有一个线程池对象。
线程池中包含了任务队列、工作线程数组、互斥锁、条件变量等成员,通过这些成员来实现任务的提交和执行。
在主函数中,提交了10个任务,每个任务都是一个简单的打印数字的函数,最后等待所有任务执行完毕后销毁线程池。
*/
java 实现线程安全的单例模式
一、平时使用的软件中,例如 回收站、线程池、文件系统等,都只有一个实例,这些都是单例模式的典型应用。
单例模式:确保某个类只有一个实例,并提供一个全局访问点来访问这个实例。
单例模式有三个要点:
1. 某个类只能有一个实例
2. 必须自行创建这个实例
3. 必须自行向整个系统提供这个实例。
以上三个要点提示着我们的代码编写需要注意,构造函数必须私有,否则在其他类中便可以调用构造函数创建实例,难以保证实例的唯一性。
二、单例模式分为饿汉模式和懒汉模式
//饿汉模式:(线程安全) public class Singleton1 { // 静态私有成员变量 private static Singleton1 instance = new Singleton1(); // 私有构造函数 private Singleton1() { } // 静态公有工厂方法,返回唯一实例 public static Singleton1 getInstance() { return instance; } }
// 懒汉模式:(线程不安全,需要通过双重检查锁定机制控制) public class Singleton2 { // 静态私有成员变量 private static Singleton2 instance = null; // 私有构造函数 private Singleton2() { } // 静态公有工厂方法,判断成员变量是否为空,不为空则实例化 public static Singleton2 getInstance() { if(instance == null) instance = new Singleton2(); return instance; } }
优缺点:
饿汉模式不需要考虑线程安全问题,调用速度和访问速度优于懒汉模式,但是由于它不管是否被调用都会提前创建类的实例,所以资源利用效率比较低,系统加载时间比较长。
懒汉模式实现了延迟加载,但是需要克服多个线程同时访问的问题,需要通过双重检查锁定机制进行控制,导致系统性能受到一定影响。
三、下面两个方法实现懒汉模式的线程安全。
为什么会线程不安全?
假设有两个线程 A B,其中 A 执行到检查方法,即 if(instance == null) 前,实例都没有被创建,那么 A 会得到 ture 的结果,但是此时调度算法选择 B 线程运行,那么当 B 执行 到 if(instance == null) 时得到的也是 true,那这就很尴尬了,两个线程都会执行 instance = new Singleton2(); 从而创建了两个实例。
1.双重检查锁定机制。
为了避免以上这种尴尬的情况,需要将这两行代码加上同步锁。但这还不够完美,每次调用函数得到实例都要试图加上一个同步锁,而加锁是一个非常耗时的操作,没有必要的情况下应该尽量避免。基于这种想法,我们可以在加锁前再次判断实例是否为空。这就是双重检查锁定机制。
public class Singleton3 { // 私有静态成员变量 private static Singleton3 instance = null; // 私有构造函数 private Singleton3() { } // 共有静态工厂方法 public static Singleton3 getInstance() { // 判断 instance 是否为空,为空->加锁,创建实例(为了进程安全,再次判断),不为空->返回实例 if(instance == null) { synchronized (Singleton3.class) { if(instance == null) instance = new Singleton3(); } } return instance; } }
2. 使用静态内部类创建实例 。(JAVA 语言中最好的实现方法)
public class Singleton4 { // 私有构造函数 private Singleton4() { } // 静态内部类 private static class HolderClass{ private static final Singleton4 instance = new Singleton4(); } // 静态公有工厂方法,返回内部类中创建的实例 public static Singleton4 getInstance() { return HolderClass.instance; } }
当装载 Singleton4 类时,instance 不一定被初始化,因为它是内部类的成员变量。Singleton4 没有被主动使用,只有调用 getInstance 方法时,才会装载 Singleton4 类,从而实例化 instance。
使用静态内部类很好得在实现了延迟加载的同时,保证初始化 instance 时只有一个线程。
以上是关于C语言-单例模式实现线程池的主要内容,如果未能解决你的问题,请参考以下文章