基于window的共享日志模块
时间:2020-08-11 19:26:36
收藏:0
阅读:65
1 /************************************************************************/ 2 /* SharedLogging.h 多进程共享日志模块 */ 3 /************************************************************************/ 4 5 #ifndef __SHARED_LOGGING_H_20200811__ 6 #define __SHARED_LOGGING_H_20200811__ 7 8 #pragma once 9 10 #ifdef SHAREDLOGGING_EXPORTS 11 #define SHAREDLOGGING_API __declspec(dllexport) 12 #else 13 #define SHAREDLOGGING_API __declspec(dllimport) 14 #endif 15 16 #include <Windows.h> 17 18 #ifdef __cplusplus 19 extern "C" { 20 #endif /* __cplusplus */ 21 22 23 typedef void (*incomingLogging)(void *user_data, wchar_t const *logging_texts, unsigned logging_length); 24 /**< 版本号 */ 25 SHAREDLOGGING_API unsigned SharedLoggingVersion(void); 26 /**< 建立连接 */ 27 SHAREDLOGGING_API HANDLE SharedLoggingConnect(const wchar_t* moudle_name); 28 /**< 断开连接 */ 29 SHAREDLOGGING_API int SharedLoggingDisconnect(HANDLE handle); 30 /**< 写入日志 */ 31 SHAREDLOGGING_API int SharedLoggingWrite(HANDLE handle, const wchar_t *logging_text, unsigned text_length); 32 /**< 订阅日志 */ 33 SHAREDLOGGING_API int SharedLoggingSubscribe(HANDLE handle, incomingLogging cb, void *user_data); 34 /**< 取消订阅 */ 35 SHAREDLOGGING_API int SharedLoggingUnsubscribe(HANDLE handle); 36 /**< 读出最后一条日志 */ 37 SHAREDLOGGING_API int SharedLoggingRead(HANDLE handle, wchar_t *logging, unsigned length); 38 39 #ifdef __cplusplus 40 } 41 #endif /* __cplusplus */ 42 43 #endif //__SHARED_LOGGING_H_20200811__
源代码,如下:
1 /************************************************************************/ 2 /* SharedLogging.cpp 多进程共享日志模块 */ 3 /************************************************************************/ 4 #include "stdafx.h" 5 #include "SharedLogging.h" 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <process.h> 9 10 #define MAX(a,b) ((a>b)?a:b) 11 #define MIN(a,b) ((a<b)?a:b) 12 13 #define VERSION_MAIN 1 14 #define VERSION_SUB 0 15 #define VERSION_NUM ((unsigned)(VERSION_MAIN << 8)|(VERSION_SUB)) 16 17 #define SHARED_LOGGING_NAME L"SharedLogging" 18 #define SHARED_LOGGING_MUTEX_NAME L"SharedLoggingMutex" 19 20 #define SHARED_LOGGING_GLOBAL_SIZE 80 21 #define SHARED_LOGGING_ITEM_NUM 256 22 #define SHARED_LOGGING_ITEM_SIZE 160 // 0x50 23 #define SHARED_LOGGING_MEMORY_SIZE ((SHARED_LOGGING_ITEM_NUM * SHARED_LOGGING_ITEM_SIZE) + SHARED_LOGGING_GLOBAL_SIZE) 24 25 26 27 struct shared_logging_base 28 { 29 wchar_t name[16]; /**< write SHARED_LOGGING_NAME to this */ 30 unsigned offsetRead; 31 HANDLE hMap; 32 HANDLE hMutex; 33 LPVOID pBuffer; 34 unsigned shutdown; 35 HANDLE hThread; 36 HANDLE hEvent; 37 CRITICAL_SECTION csLock; 38 incomingLogging cb; 39 void *user_data; 40 }; 41 typedef struct shared_logging_base sl_base_st; 42 43 struct shared_logging_global 44 { 45 unsigned version; 46 unsigned capacity_items_num; 47 unsigned total_items_num; 48 unsigned write_item_offset; 49 }; 50 typedef struct shared_logging_global sl_global_st; 51 52 #define ALLOC_ONE(type) ((type *)malloc(sizeof(type))) 53 #define EXIT_ASSERT(val) do{if (!val) exit(1);}while(0) 54 #define SET_ZERO(ptr, type) (memset(ptr, 0, sizeof(type))) 55 56 static unsigned __stdcall fnQueueHandler(void *arg); 57 58 59 static sl_base_st *CreateUserDescription(const wchar_t *name) 60 { 61 sl_base_st *base = ALLOC_ONE(sl_base_st); 62 EXIT_ASSERT(base); 63 SET_ZERO(base, sl_base_st); 64 memcpy(base->name, name, sizeof(base->name)-2); 65 return base; 66 } 67 68 69 70 static int OpenMapFile(sl_base_st *base) 71 { 72 sl_global_st *global = NULL; 73 LPVOID pBuffer = NULL; /**< 共享内存指针 */ 74 75 HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, SHARED_LOGGING_NAME); 76 if (!hMap) /**< 打开失败,创建之 */ 77 { 78 hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE, /**< 物理文件句柄 */ 79 NULL, /**< 默认安全级别 */ 80 PAGE_READWRITE, /**< 可读可写 */ 81 0, /**< 高位文件大小 */ 82 SHARED_LOGGING_MEMORY_SIZE, /**< 地位文件大小 */ 83 SHARED_LOGGING_NAME); /**< 共享内存名称 */ 84 85 EXIT_ASSERT(hMap); 86 87 } 88 if (hMap) 89 { 90 /**< 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据 */ 91 pBuffer = ::MapViewOfFile(hMap, /**< 共享内存的句柄 */ 92 FILE_MAP_ALL_ACCESS, /**< 可读写许可 */ 93 0, /**< 表示文件映射起始偏移的高32位 */ 94 0, /**< 表示文件映射起始偏移的低32位.(64KB对齐不是必须的) */ 95 0); /**< 指定映射文件的字节数 */ 96 EXIT_ASSERT(pBuffer); 97 } 98 if (pBuffer) 99 { 100 global = (sl_global_st *)pBuffer; 101 if (global->version != VERSION_NUM) 102 { 103 global->version = VERSION_NUM; 104 global->capacity_items_num = SHARED_LOGGING_ITEM_NUM; 105 global->total_items_num = 0; 106 global->write_item_offset = 0; 107 } 108 base->pBuffer = pBuffer; 109 base->hMap = hMap; 110 return 0; 111 } 112 return -1; 113 114 } 115 116 static int OpenMutex(sl_base_st *base) /**< 共享互斥锁 */ 117 { 118 HANDLE hMutex; 119 hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE,SHARED_LOGGING_MUTEX_NAME); 120 if (NULL == hMutex) 121 { 122 hMutex = CreateMutex(NULL, FALSE, SHARED_LOGGING_MUTEX_NAME); 123 EXIT_ASSERT(hMutex); 124 } 125 if (hMutex) 126 { 127 base->hMutex = hMutex; 128 return 0; 129 } 130 else 131 { 132 return -1; 133 } 134 } 135 136 static int LockMutex(sl_base_st *base) /**< 共享互斥锁 */ 137 { 138 DWORD ret = WaitForSingleObject(base->hMutex, INFINITE); 139 if (ret == WAIT_OBJECT_0) 140 { 141 return 0; 142 } 143 else if (ret == WAIT_ABANDONED) 144 { 145 return -1; 146 } 147 else{ 148 return -2; 149 } 150 } 151 static int UnlockMutex(sl_base_st *base) /**< 共享互斥锁 */ 152 { 153 return (ReleaseMutex(base->hMutex)==TRUE)?0:-1; 154 } 155 156 static int ReleaseHandle(sl_base_st *base) 157 { 158 if (base) 159 { 160 /**< 解除文件映射,关闭内存映射文件对象句柄 */ 161 if (base->pBuffer) 162 UnmapViewOfFile(base->pBuffer); 163 164 if (base->hMutex) 165 CloseHandle(base->hMutex); 166 167 if (base->hMap) 168 CloseHandle(base->hMap); 169 170 free(base); 171 return 0; 172 } 173 return -1; 174 } 175 176 static size_t WriteMapFile(sl_base_st *base, void *buffer, size_t length) 177 { 178 sl_global_st *global = (sl_global_st *)base->pBuffer; /**< 共享内存指针 */ 179 size_t wlen = MIN(length, SHARED_LOGGING_ITEM_SIZE); 180 181 unsigned offset = (global->write_item_offset * SHARED_LOGGING_ITEM_SIZE) + SHARED_LOGGING_GLOBAL_SIZE; 182 memcpy(((unsigned char *)base->pBuffer) + offset, buffer, wlen); 183 if ((global->write_item_offset + 1) >= global->capacity_items_num) 184 global->write_item_offset = 0; 185 else 186 global->write_item_offset += 1; 187 188 global->total_items_num += 1; 189 return wlen; 190 } 191 static size_t ReadMapFileForNextItem(sl_base_st *base, void *buffer, size_t length) 192 { 193 sl_global_st *global = (sl_global_st *)base->pBuffer; /**< 共享内存指针 */ 194 size_t wlen = MIN(length, SHARED_LOGGING_ITEM_SIZE); /**< 最小的长度 */ 195 unsigned offset = ((base->offsetRead) * SHARED_LOGGING_ITEM_SIZE) + SHARED_LOGGING_GLOBAL_SIZE; 196 197 memcpy(buffer, ((unsigned char *)base->pBuffer) + offset, wlen); 198 if ((base->offsetRead + 1) >= global->capacity_items_num) 199 base->offsetRead = 0; 200 else 201 base->offsetRead += 1; 202 return wlen; 203 204 } 205 static size_t ReadMapFileForLastItem(sl_base_st *base, void *buffer, size_t length) 206 { 207 sl_global_st *global = (sl_global_st *)base->pBuffer; /**< 共享内存指针 */ 208 size_t wlen = MIN(length, SHARED_LOGGING_ITEM_SIZE); /**< 最小的长度 */ 209 210 unsigned offset = 0; 211 if (global->write_item_offset > 0) /**< 非首写位置的话 */ 212 { 213 offset = ((global->write_item_offset - 1) * SHARED_LOGGING_ITEM_SIZE) + SHARED_LOGGING_GLOBAL_SIZE; 214 } 215 else if (global->total_items_num > 0) /**< 若首写位置的话,则要再加上非零记录的判断 */ 216 { 217 offset = ((global->total_items_num - 1) * SHARED_LOGGING_ITEM_SIZE) + SHARED_LOGGING_GLOBAL_SIZE; 218 } 219 else 220 return 0; 221 222 memcpy(buffer, ((unsigned char *)base->pBuffer) + offset, wlen); 223 return wlen; 224 } 225 226 227 228 static int inline CompareCurrentOffset(sl_base_st *base, unsigned offset) 229 { 230 sl_global_st *global = (sl_global_st *)base->pBuffer; /**< 共享内存指针 */ 231 232 if (global->write_item_offset == offset) 233 return 0; 234 else 235 return -1; 236 } 237 238 /**< 版本号 */ 239 SHAREDLOGGING_API unsigned SharedLoggingVersion(void) 240 { 241 return VERSION_NUM; 242 } 243 244 /**< 建立连接 */ 245 SHAREDLOGGING_API HANDLE SharedLoggingConnect(const wchar_t* moudle_name) 246 { 247 sl_base_st *base = CreateUserDescription(moudle_name); 248 249 if ((!OpenMutex(base)) &&(!OpenMapFile(base))) 250 return (HANDLE)base; 251 else 252 { 253 free(base); 254 return INVALID_HANDLE_VALUE; 255 } 256 } 257 258 /**< 断开连接 */ 259 SHAREDLOGGING_API int SharedLoggingDisconnect(HANDLE handle) 260 { 261 return ReleaseHandle((sl_base_st *)handle); 262 } 263 264 /**< 写入日志 */ 265 SHAREDLOGGING_API int SharedLoggingWrite(HANDLE handle, const wchar_t *logging, unsigned length) 266 { 267 sl_base_st *base = (sl_base_st *)handle; 268 LockMutex(base); 269 size_t rlen = WriteMapFile(base, (LPVOID)logging, sizeof(wchar_t) * length); 270 UnlockMutex(base); 271 return rlen; 272 } 273 274 /**< 读出最后一条日志 */ 275 SHAREDLOGGING_API int SharedLoggingRead(HANDLE handle, wchar_t *logging, unsigned length) 276 { 277 sl_base_st *base = (sl_base_st *)handle; 278 LockMutex(base); 279 size_t rlen = ReadMapFileForLastItem(base, (LPVOID)logging, sizeof(wchar_t) * length); 280 UnlockMutex(base); 281 return rlen; 282 } 283 284 /**< 订阅 */ 285 SHAREDLOGGING_API int SharedLoggingSubscribe(HANDLE handle, incomingLogging cb, void *user_data) 286 { 287 sl_base_st *base = (sl_base_st *)handle; 288 289 //初始化队列的临界区 290 InitializeCriticalSection(&base->csLock); 291 292 //初始化事件信号 293 HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 294 if (!hEvent) 295 { 296 DeleteCriticalSection(&base->csLock); 297 return -1; 298 } 299 300 //创建事件队列的处理线程 301 HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, fnQueueHandler, handle, 0, NULL); 302 if (!hThread) 303 { 304 CloseHandle(hEvent); 305 DeleteCriticalSection(&base->csLock); 306 return -2; 307 } 308 309 base->hThread = hThread; 310 base->hEvent = hEvent; 311 base->cb = cb; 312 base->user_data = user_data; 313 return 0; 314 } 315 316 317 /**< 取消订阅 */ 318 SHAREDLOGGING_API int SharedLoggingUnsubscribe(HANDLE handle) 319 { 320 sl_base_st *base = (sl_base_st *)handle; 321 322 EnterCriticalSection(&base->csLock);//进入临界区 323 base->shutdown = 1; 324 LeaveCriticalSection(&base->csLock);//退出临界区 325 326 SetEvent(base->hEvent); 327 //等待子线程结束 328 if (base->hThread){ 329 WaitForSingleObject(base->hThread, INFINITE); 330 //一定要记得关闭线程句柄 331 CloseHandle(base->hThread); 332 base->hThread = NULL; 333 } 334 if (base->hEvent){ 335 CloseHandle(base->hEvent); 336 base->hEvent = NULL; 337 } 338 339 DeleteCriticalSection(&base->csLock); //删除临界区 340 return -1; 341 } 342 343 static unsigned __stdcall fnQueueHandler(void *arg) 344 { 345 sl_base_st *base = (sl_base_st *)arg; 346 CRITICAL_SECTION *pLock = &base->csLock; 347 HANDLE hEvent = base->hEvent; 348 HANDLE hThread = base->hThread; 349 char buffer[SHARED_LOGGING_ITEM_SIZE]; 350 wchar_t *logging = (wchar_t *)buffer; 351 352 while (true) 353 { 354 while ((base->shutdown == 0)&&(CompareCurrentOffset(base, base->offsetRead) == 0)) 355 { 356 LeaveCriticalSection(pLock);//退出临界区 357 WaitForSingleObject(hEvent, INFINITE); 358 EnterCriticalSection(pLock);//进入临界区 359 } 360 if (base->shutdown == 1) 361 { 362 LeaveCriticalSection(pLock);//退出临界区 363 break; 364 } 365 memset(buffer, 0, SHARED_LOGGING_ITEM_SIZE); 366 LockMutex(base); 367 ReadMapFileForNextItem(base, buffer, SHARED_LOGGING_ITEM_SIZE); 368 UnlockMutex(base); 369 LeaveCriticalSection(pLock);//退出临界区 370 371 if (base->cb) 372 (base->cb)(base->user_data, logging, wcslen(logging)); 373 374 EnterCriticalSection(pLock);//进入临界区 375 } 376 377 return 0; 378 }
测试代码,如下:
1 /************************************************************************/ 2 /* Tester.cpp */ 3 /************************************************************************/ 4 #include "stdafx.h" 5 #include "SharedLogging.h" 6 7 #define SAY_HELLO L"Hello world!" 8 #define SAY_GOOD L"Good world!" 9 #define SAY_BYE L"Bye world!" 10 11 void cbLogging(void *user_data, wchar_t const*logging_texts, unsigned logging_length) 12 { 13 wprintf(L"text : %s \n", logging_texts); 14 } 15 16 int _tmain(int argc, _TCHAR* argv[]) 17 { 18 wchar_t buffer[256]; 19 int rlen = 0; 20 21 printf("Version : 0x%x\n", SharedLoggingVersion()); 22 23 HANDLE handle = SharedLoggingConnect(L"Tester"); 24 25 SharedLoggingSubscribe(handle, cbLogging, handle); 26 27 for (size_t i=0; i<10; ++i) 28 { 29 SharedLoggingWrite(handle, SAY_HELLO, wcslen(SAY_HELLO)); 30 SharedLoggingWrite(handle, SAY_GOOD, wcslen(SAY_GOOD)); 31 SharedLoggingWrite(handle, SAY_BYE, wcslen(SAY_BYE)); 32 } 33 34 getchar(); 35 36 return 0; 37 }
输出效果,如下:
1 Version : 0x100 2 text : Hello world! 3 text : Good world! 4 text : Bye world! 5 text : Hello world! 6 text : Good world! 7 text : Bye world! 8 text : Hello world! 9 text : Good world! 10 text : Bye world! 11 text : Hello world! 12 text : Good world! 13 text : Bye world! 14 text : Hello world! 15 text : Good world! 16 text : Bye world! 17 text : Hello world! 18 text : Good world! 19 text : Bye world! 20 text : Hello world! 21 text : Good world! 22 text : Bye world! 23 text : Hello world! 24 text : Good world! 25 text : Bye world! 26 text : Hello world! 27 text : Good world! 28 text : Bye world! 29 text : Hello world! 30 text : Good world! 31 text : Bye world!
关键要点:
1、互斥锁与共享内存文件的名称,不能相同,否则后者会报告(错误6)。
2、临界区与互斥锁,需要深入理解,前者是保护该进程订阅功能在多线程环境中也能使用;后者则是为了在多个进程中的应用互斥。
3、共享空间的首部结构,是为了保存它的全局变量,比如,最大容量、当前总数量,写入偏移等,往后还可以追加其他。
4、每个日志条目,都是固定长度,有点浪费空间。可以优化成动态长度,把全局变量的“写入偏移”这个变量,替换成“写指针”即可。
5、超过最大容量的时候,会覆盖最前面的内容。
原文:https://www.cnblogs.com/yuwl26/p/13478723.html
评论(0)