设计模式-单例模式-懒汉式饿汉式探讨

文章介绍了单例模式的基础概念,包括饿汉式和懒汉式的实现,强调了线程安全的重要性。提供了具体的C语言实现,如数据库连接池、线程池、日志管理器和配置管理器的单例模式示例,展示了在大型项目中如何利用单例模式管理全局资源。
摘要由CSDN通过智能技术生成

基础概念

单例模式是一种常用的设计模式,它可以保证一个类只有一个实例对象,并提供一个全局访问点来访问该实例对象。在实际开发中,常常需要使用单例模式来管理全局资源,例如数据库连接池、线程池等。

单例模式可以分为懒汉式和饿汉式两种实现方式。

懒汉式单例模式是指在第一次使用实例对象时才创建实例对象,而不是在程序启动时就创建实例对象。
懒汉式单例模式的优点是可以节省系统资源,缺点是在多线程环境下可能会出现多个线程同时创建实例对象的问题,需要进行线程安全处理。
饿汉式单例模式是指在程序启动时就创建实例对象(并申请分配内存),而不是在第一次使用实例对象时才创建实例对象。
饿汉式单例模式的优点是可以避免多线程环境下的线程安全问题,缺点是可能会浪费系统资源。

饿汉式实例

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int id;
    char* name;
} Singleton;

static Singleton* instance = NULL;

/* 只此仅当程序第一次起来,仅跑一次 */
void init_instance() {
    instance = (Singleton*)malloc(sizeof(Singleton));
    instance->id = 1;
    instance->name = "Singleton";
}

Singleton* get_instance() {
    return instance;
}

int main() {
    init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异 */
    Singleton* singleton = get_instance();
    printf("id: %d, name: %s\n", singleton->id, singleton->name);
    free(instance);
    return 0;
}

懒汉式实例

懒汉式实例【互斥锁方式保障线程安全】

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

/* 懒汉单例模式 */
/* 互斥锁方式保障线程安全 */

typedef struct {
    int id;
    char* name;
} Singleton;

static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Singleton* get_instance() {
	/* 检查实例对象存在性时,获取互斥锁,存在性能开销问题 */
    pthread_mutex_lock(&mutex);
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        instance->id = 1;
        instance->name = "Singleton";
    }
    pthread_mutex_unlock(&mutex);
    return instance;
}

int main() {
    Singleton* singleton1 = get_instance();
    Singleton* singleton2 = get_instance();
    printf("singleton1: %p, singleton2: %p\n", singleton1, singleton2);
    return 0;
}

懒汉式实例【双重检查锁定(Double-Checked Locking)保障线程安全】

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

/* 懒汉单例模式 */
/* 双重检查锁定(Double-Checked Locking)保障线程安全 */

typedef struct {
    int id;
    char* name;
} Singleton;

static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Singleton* get_instance() {
	/* 优势:
	 * 在第一次检查实例对象是否存在时,不需要获取互斥锁,
	 * 这可以避免每次调用get_instance函数时都需要获取互斥锁的性能问题。
	 * 只有在实例对象不存在时,才获取互斥锁,并再次检查实例对象是否存在,以避免多个线程同时创建实例对象的问题。 
	*/
	/* 隐患:在使用双重检查锁定方式时,需要保证编译器对静态变量的初始化顺序,否则可能会导致线程安全问题。 */
    if (instance == NULL) {	/* 第一次判空,即第一次检查 */
        pthread_mutex_lock(&mutex);
        if (instance == NULL) {	/* 第二次判空,即第二次检查 */
            instance = (Singleton*)malloc(sizeof(Singleton));
            instance->id = 1;
            instance->name = "Singleton";
        }
        pthread_mutex_unlock(&mutex);
    }
    return instance;
}

int main() {
    Singleton* singleton1 = get_instance();
    Singleton* singleton2 = get_instance();
    printf("singleton1: %p, singleton2: %p\n", singleton1, singleton2);
    return 0;
}

大型项目中单例模式实用

  1. 数据库连接池:在大型项目中,通常需要频繁地访问数据库,为了提高数据库访问效率,可以使用数据库连接池来管理数据库连接。数据库连接池可以使用单例模式来实现,保证只有一个数据库连接池实例对象,并提供一个全局访问点来访问该实例对象。

  2. 线程池:在大型项目中,通常需要使用多线程来提高系统并发能力,为了避免频繁地创建和销毁线程,可以使用线程池来管理线程。线程池可以使用单例模式来实现,保证只有一个线程池实例对象,并提供一个全局访问点来访问该实例对象。

  3. 日志管理器:在大型项目中,通常需要记录系统运行日志,为了方便管理和维护日志,可以使用日志管理器来管理系统日志。日志管理器可以使用单例模式来实现,保证只有一个日志管理器实例对象,并提供一个全局访问点来访问该实例对象。

  4. 配置管理器:在大型项目中,通常需要读取和管理系统配置信息,为了方便管理和维护配置信息,可以使用配置管理器来管理系统配置信息。配置管理器可以使用单例模式来实现,保证只有一个配置管理器实例对象,并提供一个全局访问点来访问该实例对象。

数据库连接池

/* C语言实现的简单的数据库连接池的饿汉式单例模式 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define MAX_CONNECTIONS 10

typedef struct {
    int id;
    char* url;
    char* username;
    char* password;
} Connection;

typedef struct {
    Connection* connections[MAX_CONNECTIONS];
    int count;
    pthread_mutex_t lock;
} ConnectionPool;

static ConnectionPool* instance = NULL;

Connection* create_connection(int id, const char* url, const char* username, const char* password) {
    Connection* conn = (Connection*)malloc(sizeof(Connection));
    conn->id = id;
    conn->url = strdup(url);
    conn->username = strdup(username);
    conn->password = strdup(password);
    return conn;
}

void destroy_connection(Connection* conn) {
    free(conn->url);
    free(conn->username);
    free(conn->password);
    free(conn);
}

void init_instance() {
	instance = (ConnectionPool*)malloc(sizeof(ConnectionPool));
	instance->count = 0;
	pthread_mutex_init(&instance->lock, NULL);
}

ConnectionPool* get_instance() {
    return instance;
}

Connection* get_connection() {
    ConnectionPool* pool = get_instance();
    pthread_mutex_lock(&pool->lock);
    Connection* conn = NULL;
    if (pool->count > 0) {
        conn = pool->connections[--pool->count];
    }
    pthread_mutex_unlock(&pool->lock);
    return conn;
}

void release_connection(Connection* conn) {
    ConnectionPool* pool = get_instance();
    pthread_mutex_lock(&pool->lock);
    if (pool->count < MAX_CONNECTIONS) {
        pool->connections[pool->count++] = conn;
    } else {
        destroy_connection(conn);
    }
    pthread_mutex_unlock(&pool->lock);
}

int main() {
	init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异 */
    ConnectionPool* pool = get_instance();
    for (int i = 0; i < MAX_CONNECTIONS; i++) {
        Connection* conn = create_connection(i, "localhost", "root", "password");
        pool->connections[pool->count++] = conn;
    }
    Connection* conn1 = get_connection();
    Connection* conn2 = get_connection();
    printf("conn1: %p\n", conn1);
    printf("conn2: %p\n", conn2);
    release_connection(conn1);
    release_connection(conn2);
    return 0;
}

C语言-单例模式实现线程池
#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个任务,每个任务都是一个简单的打印数字的函数,最后等待所有任务执行完毕后销毁线程池。
*/
C语言单例模式-实现日志管理器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>

// 日志级别枚举
typedef enum {
    LOG_LEVEL_DEBUG,
    LOG_LEVEL_INFO,
    LOG_LEVEL_WARN,
    LOG_LEVEL_ERROR,
    LOG_LEVEL_FATAL
} LogLevel;

// 日志管理器结构体
typedef struct {
    FILE* file; // 日志文件指针
    LogLevel level; // 日志级别
    pthread_mutex_t lock; // 互斥锁
} LogManager;

// 日志管理器单例结构体
typedef struct {
    LogManager* manager; // 日志管理器指针
} LogManagerSingleton;

static LogManagerSingleton* instance = NULL; // 日志管理器单例对象指针

// 获取当前时间字符串函数
void get_current_time_string(char* buffer, size_t size) {
    time_t now = time(NULL);
    struct tm* tm = localtime(&now);
    strftime(buffer, size, "%Y-%m-%d %H:%M:%S", tm);
}

// 写日志函数
void write_log(LogLevel level, const char* message) {
    LogManager* manager = instance->manager;
    if (level < manager->level) {
        return;
    }
    char time_str[20];
    get_current_time_string(time_str, sizeof(time_str));
    pthread_mutex_lock(&manager->lock);
    fprintf(manager->file, "[%s] ", time_str);
    switch (level) {
        case LOG_LEVEL_DEBUG:
            fprintf(manager->file, "[DEBUG] ");
            break;
        case LOG_LEVEL_INFO:
            fprintf(manager->file, "[INFO] ");
            break;
        case LOG_LEVEL_WARN:
            fprintf(manager->file, "[WARN] ");
            break;
        case LOG_LEVEL_ERROR:
            fprintf(manager->file, "[ERROR] ");
            break;
        case LOG_LEVEL_FATAL:
            fprintf(manager->file, "[FATAL] ");
            break;
    }
    fprintf(manager->file, "%s\n", message);
    fflush(manager->file);	// 将写缓存区立即写入磁盘。
    pthread_mutex_unlock(&manager->lock);
}

// 设置日志级别函数
void set_log_level(LogLevel level) {
    instance->manager->level = level;
}

init_instance() {
	instance = (LogManagerSingleton*)malloc(sizeof(LogManagerSingleton));
	instance->manager = (LogManager*)malloc(sizeof(LogManager));
	instance->manager->file = fopen("log.txt", "a");
	instance->manager->level = LOG_LEVEL_INFO;	// 日志默认级别INFO
	pthread_mutex_init(&instance->manager->lock, NULL);
}


// 获取日志管理器单例对象函数
LogManager* get_log_manager_instance() {
    return instance->manager;
}

int main() {
	init_instance();	/* 程序一开始,就必须执行。不然,与懒汉式无较大差异。 */
    LogManager* manager = get_log_manager_instance(); // 获取日志管理器单例对象
    set_log_level(LOG_LEVEL_DEBUG); // 设置日志级别为DEBUG
    write_log(LOG_LEVEL_DEBUG, "debug message"); // 写DEBUG级别日志
    write_log(LOG_LEVEL_INFO, "info message"); // 写INFO级别日志
    write_log(LOG_LEVEL_WARN, "warn message"); // 写WARN级别日志
    write_log(LOG_LEVEL_ERROR, "error message"); // 写ERROR级别日志
    write_log(LOG_LEVEL_FATAL, "fatal message"); // 写FATAL级别日志
    fclose(manager->file); // 关闭日志文件
    pthread_mutex_destroy(&manager->lock); // 销毁互斥锁
    free(manager); // 释放日志管理器内存
    free(instance); // 释放日志管理器单例对象内存
    return 0;
}

/*
该示例代码中,使用了单例模式来创建日志管理器对象,保证了整个程序中只有一个日志管理器对象。
日志管理器中包含了日志文件指针、日志级别、互斥锁等成员,通过这些成员来实现日志的写入和级别控制。
在主函数中,设置了日志级别为DEBUG,并写入了5条不同级别的日志,最后关闭日志文件、销毁互斥锁、释放内存。
*/
C语言单例模式-实现高性能配置管理器

代码中,使用了单例模式来创建配置管理器对象,保证了整个程序中只有一个配置管理器对象。配置管理器中包含了配置项数组、配置项数量、互斥锁等成员,通过这些成员来实现配置文件的读取和配置项的获取。在主函数中,获取了一个配置项的值,并打印出来,最后销毁互斥锁、释放内存。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define MAX_CONFIG_SIZE 1024

// 配置项结构体
typedef struct {
    char* key; // 配置项键
    char* value; // 配置项值
} ConfigItem;

// 配置管理器结构体
typedef struct {
    ConfigItem* items; // 配置项数组
    int count; // 配置项数量
    pthread_mutex_t lock; // 互斥锁
} ConfigManager;

// 配置管理器单例结构体
typedef struct {
    ConfigManager* manager; // 配置管理器指针
} ConfigManagerSingleton;

static ConfigManagerSingleton* instance = NULL; // 配置管理器单例对象指针

// 读取配置文件函数
void read_config_file(const char* filename) {
    ConfigManager* manager = instance->manager;
    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        return;
    }
    char line[MAX_CONFIG_SIZE];
    while (fgets(line, sizeof(line), file) != NULL) {
        char* key = strtok(line, "=");
        char* value = strtok(NULL, "\n");
        if (key != NULL && value != NULL) {
            ConfigItem item;
            item.key = strdup(key);
            item.value = strdup(value);
            pthread_mutex_lock(&manager->lock);
            manager->items[manager->count++] = item;
            pthread_mutex_unlock(&manager->lock);
        }
    }
    fclose(file);
}

// 获取配置项值函数
const char* get_config_value(const char* key) {
    ConfigManager* manager = instance->manager;
    for (int i = 0; i < manager->count; i++) {
        if (strcmp(manager->items[i].key, key) == 0) {
            return manager->items[i].value;
        }
    }
    return NULL;
}

// 获取配置管理器单例对象函数
ConfigManager* get_config_manager_instance() {
    if (instance == NULL) {
        instance = (ConfigManagerSingleton*)malloc(sizeof(ConfigManagerSingleton));
        instance->manager = (ConfigManager*)malloc(sizeof(ConfigManager));
        instance->manager->items = (ConfigItem*)malloc(sizeof(ConfigItem) * MAX_CONFIG_SIZE);
        instance->manager->count = 0;
        pthread_mutex_init(&instance->manager->lock, NULL);
        read_config_file("config.txt");
    }
    return instance->manager;
}

int main() {
    ConfigManager* manager = get_config_manager_instance(); // 获取配置管理器单例对象
    const char* value = get_config_value("key1"); // 获取配置项值
    if (value != NULL) {
        printf("key1=%s\n", value);
    }
    pthread_mutex_destroy(&manager->lock); // 销毁互斥锁
    free(manager->items); // 释放配置项数组内存
    free(manager); // 释放配置管理器内存
    free(instance); // 释放配置管理器单例对象内存
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值