基于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
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!