You are not logged in.


exnase

Active Clubbers

  • "exnase" started this thread

Posts: 696

Location: STD

Occupation: Nicht mehr Student

  • Send private message

1

Sunday, March 11th 2007, 7:51pm

Shared Memory

Hi,
da vor kurzem mal jemand gefragt hatte wie man SharedMemory in C/C++ umsetzt, hab ich mich mal drangesetzt und eine ganz kleine ShMem lib geschrieben.

shmem.h:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/************************************/
/* file		shmem.h					*/
/*									*/
/* author	ME						*/
/*									*/
/* date		11.03.2007				*/
/*									*/
/* desc		function prototypes	for	*/
/*			shared memory handling	*/
/*									*/
/* ver		1.0 initial				*/
/************************************/

#ifndef __SHMEM_H__
#define __SHMEM_H__

#ifdef __cplusplus
extern C {
#endif

#include <stdlib.h>

/************************************/
/* The maximum possible number of	*/
/* parallel opened shared memory	*/
/* regions for the process			*/
/************************************/
#define MAX_SHMEM_OPEN	10

/************************************/
/* The maximum size for the name	*/
/* of a shared memory regions + 1	*/
/************************************/
#define MAX_NAME_SIZE	32

/************************************/
/* func		shmem_open()			*/
/*									*/
/* desc		open a shared memory	*/
/*			region with given name	*/
/*			and size				*/
/*									*/
/* param	szName					*/
/*			Zero terminated string  */
/*			with an identifier for  */
/*			the shared memory.		*/
/*			Other processes can		*/
/*			access this region by	*/
/*			call shmem_open() with	*/
/*			same identifier.		*/
/*			The identifier has a	*/
/*			max length of			*/
/*			MAX_NAME_SIZE - 1 and 	*/
/*			it can contain any char */
/*			but backslashes(\).		*/
/*									*/
/*			ulBytes					*/
/*			The requested size of	*/
/*			shared memory region in */
/*			bytes.					*/
/*									*/
/* return	If successfull, the		*/
/*			function returns a		*/
/*			pointer to the shared	*/
/*			memory region,			*/
/*			otherwise NULL.			*/
/************************************/
void *shmem_open(const char* szName, const size_t ulBytes);


/************************************/
/* func		shmem_close()			*/
/*									*/
/* desc		Close a shared memory	*/
/*			region opened by		*/
/*			shmem_open().			*/
/*									*/
/* param	szName					*/
/*			A pointer as returned   */
/*			by shmem_open().		*/
/*			The pointer need not to	*/
/*			changed, for it is used */
/*			to find the correct		*/
/*			shared memory region to */
/*			close.					*/
/*									*/
/* return	If successfull, the		*/
/*			function returns 0,		*/
/*			otherwise -1.			*/
/************************************/
int shmem_close(void *pvMem);

#ifdef __cplusplus
} /* end extern c */
#endif

#endif	/* end __SHMEM_H__ */


shmem.c:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/************************************/
/* file		shmem.c					*/
/*									*/
/* author	ME						*/
/*									*/
/* date		11.03.2007				*/
/*									*/
/* desc		implements functions	*/
/*			declared in shmem.h		*/
/*									*/
/* ver		1.0 initial				*/
/************************************/

#include "shmem.h"
#include <memory.h>
#include <windows.h>

/************************************/
/* Structure for a shared memory	*/
/************************************/
struct SHMEM_T
{
	HANDLE	hMapping;				/* file mapping handle		*/
	void	*pvMappedView;			/* pointer to mapped view	*/
	size_t	ulSize;					/* size of memory region	*/
	char	szName[MAX_NAME_SIZE];	/* name of file map			*/
};



/************************************/
/* Global array containing all the	*/
/* shared memory regions.			*/
/************************************/
struct SHMEM_T atShMems[MAX_SHMEM_OPEN] = {0};



/************************************/
/* Clear shared memory structure.	*/
/************************************/
void clearShMem(struct SHMEM_T *ptShMem)
{
	ptShMem->hMapping		= NULL;
	ptShMem->ulSize			= 0;
	memset(ptShMem->szName,0,MAX_NAME_SIZE);
	ptShMem->pvMappedView	= NULL;
}



/************************************/
/* Open a shared memory region.		*/
/************************************/
void *shmem_open(const char* szName, const size_t ulBytes)
{
	int i;
	
	for (i=0;i<MAX_SHMEM_OPEN;++i)
	{
		/* search for a free shmem entry in global array */
		if (atShMems[i].hMapping == NULL)
		{
			/* copy the name and size */
			strncpy(atShMems[i].szName,szName,MAX_NAME_SIZE-1);
			atShMems[i].ulSize = ulBytes;

			/* create a file mapping object */
			atShMems[i].hMapping = 
				CreateFileMapping(	(HANDLE)0xFFFFFFFF,
									NULL,
									PAGE_READWRITE,
									0,
									atShMems[i].ulSize,
									atShMems[i].szName);

			if (atShMems[i].hMapping == INVALID_HANDLE_VALUE)
			{
				clearShMem(&atShMems[i]);
				return NULL;
			}
			
			/* map a view of the file to process address space */
			atShMems[i].pvMappedView = 
				MapViewOfFile(	atShMems[i].hMapping,
								FILE_MAP_ALL_ACCESS,
								0,
								0,
								0);

			if (atShMems[i].pvMappedView == NULL)
			{
				clearShMem(&atShMems[i]);
				return NULL;
			}

			/* shared memory successfully opened */
			return (atShMems[i].pvMappedView);
		}
	}

	/* if we get here there was no free */
	/* shmem structure in the array		*/
	return NULL;
}



/************************************/
/* Close a shraed memory region.	*/
/************************************/
int shmem_close(void *pvMem)
{
	int i;
		
	for (i=0;i<MAX_SHMEM_OPEN;++i)
	{
		/* find the corect shared memory region */
		if (atShMems[i].pvMappedView == pvMem)
		{
			/* unmap the view and close the handle */
			if (UnmapViewOfFile(atShMems[i].pvMappedView) &&
				CloseHandle(atShMems[i].hMapping))
			{
				clearShMem(&atShMems[i]);
				return 0;
			}
		}
	}

	/* if we get here the shmem was not */
	/* found or could not be closed		*/
	return -1;
}


main.c:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include "shmem.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>

#define NAME	"TEST_SHMEM"
#define STRING	"This a shared memory test"
#define SIZE	strlen(STRING)+1
#define WAIT1	20
#define WAIT2	5

int main(int argc, char **argv)
{
	char *shmem = NULL;

	if (argc==1)
	{
		printf("open shared mem\n");
		shmem = shmem_open(NAME,SIZE);
		if (!shmem)
		{
			printf("error during open");
			return -1;
		}

		printf("open ok. writing to shmem\n");
		strcpy(shmem,STRING);

		printf("waiting %d seconds\n",WAIT1);
		Sleep(WAIT1*1000);

		printf("close shmem\n");
		if (shmem_close(shmem) != 0)
		{
			printf("error on close\n");
			return -1;
		}
	}
	else
	{
		printf("waiting %d seconds\n",WAIT2);
		Sleep(WAIT2*1000);

		printf("open shared mem\n");
		shmem = shmem_open(NAME,SIZE);
		if (!shmem)
		{
			printf("error during open");
			return -1;
		}

		printf("open ok. content of shmem:\n");
		printf("\t>%s<\n",shmem);

		printf("close shmem\n");
		if (shmem_close(shmem) != 0)
		{
			printf("error on close\n");
			return -1;
		}
	}

	return 0;
}


Das Demoprogramm 2mal starten, einmal ohne und einmal mit Parameter.
Was für Parameter ist egal, es checkt nur die Anzahl.
Beide Instanzen öffnen das SharedMem, die ohne Parameter schreibt was rein und wartet dann eine Weile.
Die Instanz mit Parameter wartet erst kurz liest dann den String im SharedMem und schreibt ihn auf die Konsole.

Hab es mit VisualC++ 6 und DevCPP 4.9irgendwas getestet.
Bekannte Probleme:
- läuft nur auf Windows
- die Anzahl der gleichzeitig möglichen SharedMems ist begrenzt, da ich zum Speichern der Strukturen ein Array verwendet hab. Aber man kann natürlich auch eine Liste nehmen womit sich das erldedigt hätte.
- die Fehlerrückgaben sind nicht sehr aufschlußreich, sondern zeigen nur einen Fehler an. Aber das sollte auch nicht unbedingt schwierig nachzurüsten sein.

@Mods: evtl -> Codebox

mfg exnase
Wer nichts weiß und weiß, dass er nichts weiß, weiß mehr als einer, der nichts weiß und nicht weiß, dass er nichts weiß!
Meine Software hat keine Fehler. Sie entwickelt nur manchmal zufällige Features!

This post has been edited 1 times, last edit by "exnase" (Mar 11th 2007, 7:54pm)


exnase

Active Clubbers

  • "exnase" started this thread

Posts: 696

Location: STD

Occupation: Nicht mehr Student

  • Send private message

2

Tuesday, March 13th 2007, 3:00pm

So, dachte mir das geht auch besser:

shmem.h

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/************************************/
/* file     shmem.h                 */
/*                                  */
/* author   ME                      */
/*                                  */
/* date     13.03.2007              */
/*                                  */
/* desc     defines andfunction     */
/*          prototypes for shared   */
/*          memory handling         */
/*                                  */
/* ver      1.0 initial             */
/*          1.1 errorcodes          */
/*              shmem_init()        */
/*              shmem_read()        */
/*              shmem_write()       */
/************************************/

#ifndef __SHMEM_H__
#define __SHMEM_H__

#ifdef __cplusplus
extern C {
#endif

#include <stdlib.h>

/************************************/
/* function return codes            */
/************************************/
#define SHMEM_OK         0      /* functions succeeded                  */
#define SHMEM_INIT      -1      /* call shmem_init() first              */
#define SHMEM_ERR       -2      /* general error                        */
#define SHMEM_HANDLE    -3      /* invalid handle                       */
#define SHMEM_PARM      -4      /* parameter error                      */
#define SHMEM_MUTEX     -5      /* could not get ownership of mutex     */
#define SHMEM_MAX       -6      /* max number of shmems already opened  */

/************************************/
/* The maximum possible number of   */
/* parallel opened shared memory    */
/* regions for the process          */
/************************************/
#define MAX_SHMEM_AVAIL 10


/************************************/
/* func     shmem_init()            */
/*                                  */
/* desc     Initialize internal     */
/*          data structures. Must   */
/*          called efore any other  */
/*          other function. All     */
/*          functions return        */
/*          SHMEM_INIT if this      */
/*          function was not called */
/*          before.                 */
/************************************/
void shmem_init(void);


/************************************/
/* func     shmem_open()            */
/*                                  */
/* desc     open a shared memory    */
/*          region with given name  */
/*          and size                */
/*                                  */
/* param    iId                     */
/*          Numerical ID for the    */
/*          shmem. All processes    */
/*          must use the same ID    */
/*          for sharing a single    */
/*          memory region.          */
/*                                  */
/*          ulBytes                 */
/*          The requested size of   */
/*          shared memory region in */
/*          bytes.                  */
/*                                  */
/*          fAsync                  */
/*          Specify (a)snchronous   */
/*          r/w operations. 0 means */
/*          synchronous             */
/*                                  */
/* return   Handle to shmem on      */
/*          success.                */
/*                                  */
/*          SHMEM_ERR if shmem      */
/*          could not be opened.    */
/*                                  */
/*          SHMEM_MAX if maximum    */
/*          number of shmems is     */
/*          already open.           */
/************************************/
int shmem_open(unsigned int iId, size_t ulBytes, int fAsync);


/************************************/
/* func     shmem_close()           */
/*                                  */
/* desc     Close a shared memory   */
/*          region opened by        */
/*          shmem_open().           */
/*                                  */
/* param    iHandle                 */
/*          Handle for shmem to     */
/*          close as returned by    */
/*          shmem_open().           */
/*                                  */
/* return   SHMEM_OK on success.    */
/*                                  */
/*          SHMEM_HANDLE if a the   */
/*          handle is invalid.      */
/*                                  */
/*          SHMEM_ERR if shmem      */
/*          could not be closed.    */
/************************************/
int shmem_close(int iHandle);


/************************************/
/* func     shmem_write()           */
/*                                  */
/* desc     Write to a shared       */
/*          memory region.          */
/*                                  */
/* param    iHandle                 */
/*          Handle for shmem to     */
/*          write to.               */
/*                                  */
/*          pvBuf                   */
/*          Buffer with date to     */
/*          write.                  */
/*                                  */
/*          ulOffset                */
/*          Offset in shmem region  */
/*          to write to.            */
/*                                  */
/*          ulBytes                 */
/*          Number of bytes to      */
/*          write.                  */
/*                                  */
/* return   SHMEM_OK on success.    */
/*                                  */
/*          SHMEM_HANDLE if a the   */
/*          handle is invalid.      */
/*                                  */
/*          SHMEM_PARM if ulOffset  */
/*          and ulBytes would cause */
/*          a write out of the      */
/*          shmem region.           */
/*                                  */
/*          SHMEM_MUTEX if fAsync   */
/*          was specified in        */
/*          shmem_open() and we     */
/*          could not get immediate */
/*          ownership of the mutex. */
/************************************/
int shmem_write(int iHandle, void *pvBuf, size_t ulOffset, size_t ulBytes);


/************************************/
/* func     shmem_read()            */
/*                                  */
/* desc     Read from a shared      */
/*          memory region.          */
/*                                  */
/* param    iHandle                 */
/*          Handle for shmem to     */
/*          read from.              */
/*                                  */
/*          pvBuf                   */
/*          Buffer for date to      */
/*          read.                   */
/*                                  */
/*          ulOffset                */
/*          Offset in shmem region  */
/*          to read from.           */
/*                                  */
/*          ulBytes                 */
/*          Number of bytes to      */
/*          read.                   */
/*                                  */
/* return   SHMEM_OK on success.    */
/*                                  */
/*          SHMEM_HANDLE if a the   */
/*          handle is invalid.      */
/*                                  */
/*          SHMEM_PARM if ulOffset  */
/*          and ulBytes would cause */
/*          a read out of the       */
/*          shmem region.           */
/*                                  */
/*          SHMEM_MUTEX if fAsync   */
/*          was specified in        */
/*          shmem_open() and we     */
/*          could not get immediate */
/*          ownership of the mutex. */
/************************************/
int shmem_read(int iHandle, void *pvBuf, size_t ulOffset, size_t ulBytes);


#ifdef __cplusplus
} /* END extern C */
#endif

#endif  /* END __SHMEM_H__ */


shmem.c

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
/************************************/
/* file     shmem.c                 */
/*                                  */
/* author   ME                      */
/*                                  */
/* date     13.03.2007              */
/*                                  */
/* desc     implements functions    */
/*          declared in shmem.h     */
/*                                  */
/* ver      1.0 initial             */
/*          1.1 Linux/Unix support  */
/*              API redesign        */
/************************************/

#include "shmem.h"

#include <memory.h>
#include <errno.h>

#ifdef WIN32
#include <windows.h>
#endif

#ifdef unix
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <fcntl.h>
#include <stdio.h>
#endif



/************************************/
/* Structure for a shared memory    */
/************************************/
#ifdef WIN32

#define SHMEM_NAME_SIZE     32

struct SHMEM_T
{
    HANDLE  hMapping;                   /* file mapping handle      */
    HANDLE  hMutex;                     /* mutex handle             */
    char    *pcMappedView;              /* pointer to mapped view   */
    size_t  ulSize;                     /* size of memory region    */
    int     fAsync;                     /* flag for async r/w       */
    char    szName[SHMEM_NAME_SIZE];    /* name of file map         */
};

#endif



#ifdef unix

struct SHMEM_T
{
    key_t   iKey;                       /* key of shmem             */
    int     iShMemIdent;                /* identifier of shmem      */
    sem_t   *ptSemIdent;                /* identifier of semaphore  */
    int     fAsync;                     /* flag for async r/w       */
    size_t  ulSize;                     /* size of memory region    */
    char    *pcMappedView;              /* pointer to mapped view   */
};

#endif


/************************************/
/* Global array containing all the  */
/* shared memory regions.           */
/************************************/
struct SHMEM_T gatShMems[MAX_SHMEM_AVAIL];

/************************************/
/* Global array containing all the  */
/* shared memory regions.           */
/************************************/
int gfInitDone = 0;

/************************************/
/* private functions prototypes     */
/************************************/
void shmem_clear(struct SHMEM_T *ptShMem);


/****************************************************************************/
/*                      SYSTEM INDEPENDANT FUNCTIONS                        */
/****************************************************************************/
void shmem_init(void)
{
    int i;

    for (i=0; i<MAX_SHMEM_AVAIL; i++)
    {
        shmem_clear(&gatShMems[i]);
    }

    gfInitDone = 1;
}



/****************************************************************************/
/*                              WIN32 FUNCTIONS                             */
/****************************************************************************/


#ifdef WIN32


/************************************/
/* Clear shared memory structure.   */
/************************************/
void shmem_clear(struct SHMEM_T *ptShMem)
{
    ptShMem->pcMappedView = NULL;
    ptShMem->hMapping     = INVALID_HANDLE_VALUE;
    ptShMem->hMutex       = INVALID_HANDLE_VALUE;
    ptShMem->ulSize       = 0;
    ptShMem->fAsync       = 0;
    memset(ptShMem->szName,0,SHMEM_NAME_SIZE);
} /* END shmem_clear() */


/************************************/
/* Open a shared memory region.     */
/************************************/
int shmem_open(unsigned int iId, size_t ulBytes, int fAsync)
{
    int i;
    char szName[16];

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    _itoa(iId,szName,16);

    for (i=0;i<MAX_SHMEM_AVAIL;++i)
    {
        /* search for a free shmem entry in global array */
        if (gatShMems[i].hMapping == INVALID_HANDLE_VALUE)
        {
            /* init struct */
            strcpy(gatShMems[i].szName,szName);
            gatShMems[i].ulSize = ulBytes;
            gatShMems[i].fAsync = fAsync;

            /* create a file mapping object */
            gatShMems[i].hMapping = 
                CreateFileMapping( (HANDLE)0xFFFFFFFF,
                                   NULL,
                                   PAGE_READWRITE,
                                   0,
                                   gatShMems[i].ulSize,
                                   gatShMems[i].szName);

            if (gatShMems[i].hMapping == INVALID_HANDLE_VALUE)
            {
                shmem_clear(&gatShMems[i]);
                return SHMEM_ERR;
            }

            /* map a view of the file to process address space */
            gatShMems[i].pcMappedView = 
                MapViewOfFile( gatShMems[i].hMapping,
                               FILE_MAP_ALL_ACCESS,
                               0,
                               0,
                               0);

            if (gatShMems[i].pcMappedView == NULL)
            {
                /* rollback */
                CloseHandle(gatShMems[i].hMapping);
                shmem_clear(&gatShMems[i]);
                return SHMEM_ERR;
            }

            /* create a mutex for the shmem */
            strcat(gatShMems[i].szName,"MUTEX");
            gatShMems[i].hMutex = 
                CreateMutex( NULL,
                             FALSE,
                             gatShMems[i].szName);

            if (gatShMems[i].hMutex == INVALID_HANDLE_VALUE)
            {
                /* rollback */
                UnmapViewOfFile(gatShMems[i].pcMappedView);
                CloseHandle(gatShMems[i].hMapping);
                shmem_clear(&gatShMems[i]);
                return SHMEM_ERR;
            }

            /* shared memory successfully opened */
            return (i+1);
        } /* END if (gatShMems[i].hMapping) */
    } /* END for */

    /* if we get here there was no free */
    /* shmem structure in the array     */
    return SHMEM_MAX;
} /* END shmem_open() */


/************************************/
/* Close a shared memory region.    */
/************************************/
int shmem_close(int iHandle)
{
    int i = iHandle-1;

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    if (i < 0                                         ||
        i >= MAX_SHMEM_AVAIL                          ||
        gatShMems[i].hMapping == INVALID_HANDLE_VALUE )
    {
        /* invalid handle */
        return SHMEM_HANDLE;
    }
        
    /* unmap the view and close the handles */
    if (UnmapViewOfFile(gatShMems[i].pcMappedView) &&
        CloseHandle(gatShMems[i].hMapping)         &&
        CloseHandle(gatShMems[i].hMutex)           )
    {
        shmem_clear(&gatShMems[i]);
        return SHMEM_OK;
    }

    /* if we get here the shmem could not be closed */
    return SHMEM_ERR;
} /* END shmem_close() */

/************************************/
/* Write to a shared memory region. */
/************************************/
int shmem_write(int iHandle, void *pvBuf, size_t ulOffset, size_t ulBytes)
{
    int i = iHandle-1;
    DWORD dwWaitRes = 0;

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    if (i < 0                                         || 
        i >= MAX_SHMEM_AVAIL                          ||
        gatShMems[i].hMapping == INVALID_HANDLE_VALUE )
    {
        /* invalid handle */
        return SHMEM_HANDLE;
    }

    if ((ulOffset + ulBytes) > gatShMems[i].ulSize)
    {
        /* would write over memory region */
        return SHMEM_PARM;
    }

    /* params ok. get mutex */
    dwWaitRes = 
        WaitForSingleObject( gatShMems[i].hMutex,
                             ((gatShMems[i].fAsync) ? 0 : INFINITE));

    if (dwWaitRes == WAIT_OBJECT_0)
    {
        /* we got the mutex so copy the data */
        memcpy(gatShMems[i].pcMappedView + ulOffset, pvBuf, ulBytes);

        /* release the mutex */
        ReleaseMutex(gatShMems[i].hMutex);
    }
    else
    {
        /* we didnt get the mutex */
        return SHMEM_MUTEX;
    }

    return SHMEM_OK;
} /* END shmem_write() */

/************************************/
/* Read from a shared memory region.*/
/************************************/
int shmem_read(int iHandle, void *pvBuf, size_t ulOffset, size_t ulBytes)
{
    int i = iHandle-1;
    DWORD dwWaitRes = 0;

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    if (i < 0                                         || 
        i >= MAX_SHMEM_AVAIL                          ||
        gatShMems[i].hMapping == INVALID_HANDLE_VALUE )
    {
        /* invalid handle */
        return SHMEM_HANDLE;
    }

    if ((ulOffset + ulBytes) > gatShMems[i].ulSize)
    {
        /* would read over memory region */
        return SHMEM_PARM;
    }

    /* params ok. get mutex */
    dwWaitRes = 
        WaitForSingleObject( gatShMems[i].hMutex,
                             ((gatShMems[i].fAsync) ? 0 : INFINITE));

    if (dwWaitRes == WAIT_OBJECT_0)
    {
        /* we got the mutex so copy the data */
        memcpy(pvBuf, gatShMems[i].pcMappedView + ulOffset, ulBytes);

        /* release the mutex */
        ReleaseMutex(gatShMems[i].hMutex);
    }
    else
    {
        /* we didnt get the mutex */
        return SHMEM_MUTEX;
    }

    return SHMEM_OK;
} /* END shmem_read() */


#endif /* END WIN32 */



/****************************************************************************/
/*                          UNIX/LINUX FUNCTIONS                            */
/****************************************************************************/


#ifdef unix


/************************************/
/* Clear shared memory structure.   */
/************************************/
void shmem_clear(struct SHMEM_T *ptShMem)
{
    ptShMem->pcMappedView = NULL;
    ptShMem->iShMemIdent  = -1;
    ptShMem->ptSemIdent   = SEM_FAILED;
    ptShMem->iKey         = -1;
    ptShMem->ulSize       = 0;
    ptShMem->fAsync       = 0;
} /* END shmem_clear() */

/************************************/
/* Open a shared memory region.     */
/************************************/
int shmem_open(unsigned int iId, size_t ulBytes, int fAsync)
{
    int i;
    char szSemName[32];

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    sprintf(szSemName,"/%x%s",iId,"MUTEX");

    for (i=0;i<MAX_SHMEM_AVAIL;++i)
    {
        /* search for a free shmem entry in global array */
        if (gatShMems[i].iKey == -1)
        {
            /* init struct */
            gatShMems[i].iKey   = iId;
            gatShMems[i].ulSize = ulBytes;
            gatShMems[i].fAsync = fAsync;

            /* get a shared memory. access rights: rwxrwx---*/
            gatShMems[i].iShMemIdent = 
                shmget(gatShMems[i].iKey, 
                            gatShMems[i].ulSize,
                            IPC_CREAT | S_IRWXU | S_IRWXG /* | S_IRWXO */);
            
            if (gatShMems[i].iShMemIdent == -1)
            {
                shmem_clear(&gatShMems[i]);
                return SHMEM_ERR;
            }

            /* attach shmem to process address space */
            gatShMems[i].pcMappedView =
                    shmat( gatShMems[i].iShMemIdent,
                           NULL,
                           0);

            if (gatShMems[i].pcMappedView == ((void *) -1))
            {
               	/* rollback */
                shmctl(gatShMems[i].iShMemIdent, IPC_RMID, NULL);
                shmem_clear(&gatShMems[i]);
                return SHMEM_ERR;
            }

            /* get a semaphore. access rights: rwxrwx--- */
            gatShMems[i].ptSemIdent = 
                sem_open(szSemName, 
                     O_CREAT,
                     S_IRWXU | S_IRWXG /* | S_IRWXO */, 
                     (unsigned int) 1);

            if (gatShMems[i].ptSemIdent == SEM_FAILED)
            {
               	/* rollback */
                shmdt(gatShMems[i].pcMappedView);
                shmctl(gatShMems[i].iShMemIdent, IPC_RMID, NULL);
                shmem_clear(&gatShMems[i]);
                return SHMEM_ERR;
            }

            /* shared memory successfully opened */
            return (i+1);
        } /* END if (gatShMems[i].iKey) */
    } /* END for */

    /* if we get here there was no free */
    /* shmem structure in the array     */
    return SHMEM_MAX;
} /* END shmem_open() */

/************************************/
/* Close a shared memory region.    */
/************************************/
int shmem_close(int iHandle)
{
    int i = iHandle-1;
    struct shmid_ds tShMem;

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }
    if (i < 0                   ||
        i >= MAX_SHMEM_AVAIL    ||
        gatShMems[i].iKey == -1 )
    {
        /* invalid handle */
        return SHMEM_HANDLE;
    }

    /* detach shmem, close shmem and semaphore */
    if ( shmdt(gatShMems[i].pcMappedView)   == 0                   &&
         shmctl(gatShMems[i].iShMemIdent, IPC_STAT, &tShMem) != -1 &&
         sem_close(gatShMems[i].ptSemIdent) == 0                   )
    {
        /* if we were the last process attached to this shmem, delet it */
        if (tShMem.shm_nattch == 0)
        {
            shmctl(gatShMems[i].iShMemIdent, IPC_RMID, NULL);
        }
        shmem_clear(&gatShMems[i]);
        return SHMEM_OK;
    }

    /* if we get here the shmem could not be closed */
    return SHMEM_ERR;
} /* END shmem_clear() */

/************************************/
/* Write to a shared memory region. */
/************************************/
int shmem_write(int iHandle, void *pvBuf, size_t ulOffset, size_t ulBytes)
{
    int i = iHandle-1;
    int iWaitRes = 0;

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    if (i < 0                   ||
        i >= MAX_SHMEM_AVAIL    ||
        gatShMems[i].iKey == -1 )
    {
        /* invalid handle */
        return SHMEM_HANDLE;
    }

    if ((ulOffset + ulBytes) > gatShMems[i].ulSize)
    {
        /* would write over memory region */
        return SHMEM_PARM;
    }
    
    /* params ok. get semaphore */
    if (gatShMems[i].fAsync)
    {
        iWaitRes = sem_trywait(gatShMems[i].ptSemIdent);
    }
    else
    {
        iWaitRes = sem_wait(gatShMems[i].ptSemIdent);
    }

    if (iWaitRes == 0)
    {
        /* we got the mutex so copy the data */
        memcpy(gatShMems[i].pcMappedView + ulOffset, pvBuf, ulBytes);

        /* release the semaphore */
        sem_post(gatShMems[i].ptSemIdent);
    }
    else
    {
        /* we didnt get the mutex */
        return SHMEM_MUTEX;
    }
    
    return SHMEM_OK;
} /* END shmem_write() */

/************************************/
/* Read from a shared memory region.*/
/************************************/
int shmem_read(int iHandle, void *pvBuf, size_t ulOffset, size_t ulBytes)
{
    int i = iHandle-1;
    int iWaitRes = 0;

    /* check if init is done */
    if (!gfInitDone)
    {
        return SHMEM_INIT;
    }

    if (i < 0                   ||
        i >= MAX_SHMEM_AVAIL    ||
        gatShMems[i].iKey == -1 )
    {
        /* invalid handle */
        return SHMEM_HANDLE;
    }

    if ((ulOffset + ulBytes) > gatShMems[i].ulSize)
    {
        /* would read over memory region */
        return SHMEM_PARM;
    }
    
    /* params ok. get semaphore */
    if (gatShMems[i].fAsync)
    {
        iWaitRes = sem_trywait(gatShMems[i].ptSemIdent);
    }
    else
    {
        iWaitRes = sem_wait(gatShMems[i].ptSemIdent);
    }

    if (iWaitRes == 0)
    {
        /* we got the mutex so copy the data */
        memcpy(pvBuf, gatShMems[i].pcMappedView + ulOffset, ulBytes);

        /* release the semaphore */
        sem_post(gatShMems[i].ptSemIdent);
    }
    else
    {
        /* we didnt get the mutex */
        return SHMEM_MUTEX;
    }

    return SHMEM_OK;
} /* END shmem_read() */


#endif /* END unix */


main.c

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "shmem.h"
#include <stdio.h>
#include <string.h>

#ifdef WIN32
#include <windows.h>
#define sleep(x) Sleep((x)*1000)
#endif

#ifdef unix
#include <unistd.h>
#endif

#define NAME    10000
#define STRING  "This a shared memory test"
#define SIZE    strlen(STRING)+1
#define WAIT1   20
#define WAIT2   5

int main(int argc, char **argv)
{
    int shmem = -1;

    shmem_init();

    if (argc==1)
    {
        printf("open shared mem\n");
        shmem = shmem_open(NAME,SIZE,0);
        if (shmem<0)
        {
            printf("error during open");
            return -1;
        }

        printf("open ok. writing to shmem\n");
        shmem_write(shmem,STRING,0,SIZE);

        printf("waiting %d seconds\n",WAIT1);
        sleep(WAIT1);

        printf("close shmem\n");
        if (shmem_close(shmem) != SHMEM_OK)
        {
            printf("error on close\n");
            return -1;
        }
    }
    else
    {
        char *text = malloc(SIZE);

        printf("waiting %d seconds\n",WAIT2);
        sleep(WAIT2);

        printf("open shared mem\n");
        shmem = shmem_open(NAME,SIZE,0);
        if (shmem<0)
        {
            printf("error during open");
            free(text);
            return -1;
        }

        printf("open ok. content of shmem:\n");
        shmem_read(shmem,text,0,SIZE);

        printf("\t>%s<\n",text);

        printf("close shmem\n");
        if (shmem_close(shmem) != SHMEM_OK)
        {
            printf("error on close\n");
            free(text);
            return -1;
        }
        free(text);
    }

    return 0;
}


Erweiterungen:
- Linux/Unix Support
- detailliertere Fehlermeldungen
- schreiben und lesen nicht mehr über direkten Zugriff sondern Funktionen
- Synchronisation von Lesen/Schreiben über ein Mutex
- asynchroner Zugriff möglich

Probleme:
- immer noch begrenzte Anzahl an SharedMems
- unter Unix/Linux zusätzliche Library nötig für Posix Semaphore

Getestet unter:
Windows mit
VisualC++ 6
DevCpp 4.9.9.2

Sun:
~ > cc -V
cc: Sun C 5.8

Kubuntu:
~$ gcc -dumpversion
4.1.2

Beim kompilieren unter Unix/Linux muss der Parameter -lrt angegeben werden. Hatte keinen Bock auf SystemV Semaphore :)

Fragen/Bugs gern an mich.
mfg exnase
Wer nichts weiß und weiß, dass er nichts weiß, weiß mehr als einer, der nichts weiß und nicht weiß, dass er nichts weiß!
Meine Software hat keine Fehler. Sie entwickelt nur manchmal zufällige Features!

Social bookmarks

Rate this thread