C language: singleton mode (lazy style)

introduction

In the last article " C Language: Singleton Mode (Hungry Chinese Style) ", we introduced the hungry Chinese style implementation of singletons. This article will continue to introduce the lazy man style implementation of singletons.

Lazy

Lazy man style, the original intention is that this kind of implementation is like a lazy man, never creating an object until a critical moment. There are two commonly used implementation methods: the first method is to declare the object as a static variable, and realize the singleton by using the characteristic that the static call is only initialized once. The singleton object created in this way is in the global static area. The second method is through Stack implementation, when the pointer object is called as NULL for the first time, apply to create the object from the heap memory through malloc, and the pointer object is not NULL at other call times, and will not be recreated. Objects created in this way live on the heap.

static way

Static initialization mainly borrows the characteristics of struct initialization and static call initialization only once. Since struct has two methods of sequential initialization and out-of-order initialization, the static method will also have two subdivisions.

statement

typedef  void  File;

typedef enum BOOL
{
    
    
	FALSE = 0,
	TRUE = 1,
}BOOL;

typedef struct tagFileManager
{
    
    
	File* (*mkFile)(const char* fileName, char const* mode);
	BOOL  (*rmFile)(const char*  fileName);
	int   (*write)(File* file, const char* buf, int size);
	BOOL  (*exit)(const char* fileName);
	BOOL  (*close)(const File* file);
}FileManager;

FileManager* fileManager();

accomplish

FileManager* fileManager() multi-threaded access needs to ensure thread safety. The static keyword in C language does not have thread safety. Only the static of C++11 adopts the thread safety feature.

#include <pthread.h>
#include <io.h>

static File* mkFile(const char* fileName, char const* mode);
static BOOL rmFile(const char* fileName);
static int fileWrite(File* file, const char* buf, int size);
static BOOL isExit(const char* fileName);
static BOOL fileClose(const File* file);


pthread_mutex_t g_mutex= PTHREAD_MUTEX_INITIALIZER;

File* mkFile(const char* fileName, char const* mode)
{
    
    
	FILE* file = NULL;
	if (0 == fopen_s(&file, fileName, mode))
	{
    
    
		return file;
	}
	
	return NULL;
}

BOOL rmFile(const char* fileName)
{
    
    
	if (isExit(fileName))
	{
    
    
		return !remove(fileName);
	}
}

int fileWrite(File* file, const char* buf, int size)
{
    
    
	return fwrite(buf, size, 1, file);
}

BOOL isExit(const char* fileName)
{
    
    
	return (_access(fileName, 0) == 0);
}

BOOL fileClose(const File* file)
{
    
    
	return !fclose(file);
}

FileManager* fileManager()
{
    
    
	pthread_mutex_lock(&g_mutex);
	
	// C语言乱序初始化
	static FileManager fileManager = {
    
    
		.exit = isExit,
		.mkFile = mkFile,
		.write = fileWrite,
		.rmFile = rmFile, 
		.close = fileClose
	};
	// C语言顺序初始化
	//static FileManager fileManager = {mkFile, rmFile,fileWrite,isExit, fileClose};

	pthread_mutex_unlock(&g_mutex);

	return &fileManager;
}

stack mode

The stack method is to use the way of running to dynamically manage the memory, and then create the object when the program really needs the object, and once the creation is successful, there is no need to create it for subsequent access, so as to ensure the global uniqueness.

statement

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

typedef  void  File;

typedef enum BOOL
{
    
    
	FALSE = 0,
	TRUE = 1,
}BOOL;

typedef struct tagFileManager
{
    
    
	File* (*mkFile)(const char* fileName, char const* mode);
	BOOL  (*rmFile)(const char*  fileName);
	int   (*write)(File* file, const char* buf, int size);
	BOOL  (*exit)(const char* fileName);
	BOOL  (*close)(const File* file);
}FileManager;

FileManager* fileManager();
void releaseFileManager();

accomplish

#include <pthread.h>
#include <io.h>

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

static FileManager* g_fileManager = NULL;

static File* mkFile(const char* fileName, char const* mode);
static BOOL rmFile(const char* fileName);
static int fileWrite(File* file, const char* buf, int size);
static BOOL isExit(const char* fileName);
static BOOL fileClose(const File* file);


File* mkFile(const char* fileName, char const* mode)
{
    
    
	FILE* file = NULL;
	if (0 == fopen_s(&file, fileName, mode))
	{
    
    
		return file;
	}
	
	return NULL;
}

BOOL rmFile(const char* fileName)
{
    
    
	if (isExit(fileName))
	{
    
    
		return !remove(fileName);
	}
}

int fileWrite(File* file, const char* buf, int size)
{
    
    
	return fwrite(buf, size, 1, file);
}

BOOL isExit(const char* fileName)
{
    
    
	return (_access(fileName, 0) == 0);
}

BOOL fileClose(const File* file)
{
    
    
	return !fclose(file);
}


FileManager* fileManager()
{
    
    
	pthread_mutex_lock(&g_mutex);

	// C语言堆栈方式
	if (NULL == g_fileManager)
	{
    
    
		g_fileManager = (FileManager*)malloc(sizeof(FileManager));
		if (NULL != g_fileManager)
		{
    
    
			g_fileManager->exit = isExit;
			g_fileManager->mkFile = mkFile;
			g_fileManager->write = fileWrite;
			g_fileManager->rmFile = rmFile;
			g_fileManager->close = fileClose;
		}
	}

	pthread_mutex_unlock(&g_mutex);

	return g_fileManager;
}

void releaseFileManager()
{
    
    
	pthread_mutex_lock(&g_mutex);

	if (NULL != g_fileManager)
	{
    
    
		free(g_fileManager);
		g_fileManager = NULL;
	}

	pthread_mutex_unlock(&g_mutex);
}

Summarize

This article introduces two lazy-style C language singleton implementations. In order to simplify, the implementation of singletons in this paper adopts exclusive lock implementation. The lock performance of this method is not very good. If your software has a lot of concurrency, it is recommended to use read Write lock or double lock mechanism.

Guess you like

Origin blog.csdn.net/liuguang841118/article/details/126773633