标签:
本文主要实现一个基于共享内存的计数器,通过父子进程对其访问。
本文程序需基于<<Unix网络编程-卷2>>的环境才能运行。程序中大写开头的函数为其小写同名函数的包裹函数,增加了错误处理信息。
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 | #include <sys/mman>/** * Map addresses starting near ADDR and extending for LEN bytes. * from OFFSET into the file FD describes according to PROT and FLAGS. * If ADDR is nonzero, it is the desired mapping address. * If the MAP_FIXED bit is set in FLAGS, the mapping will be at ADDR exactly (which must be * page-aligned); otherwise the system chooses a convenient nearby address. * The return value is the actual mapping address chosen or MAP_FAILED * for errors (in which case `errno‘ is set). A successful `mmap‘ call * deallocates any previous mapping for the affected region. */void *mmap (void *__addr, size_t __len, int __prot, int __flags, int __fd, __off_t __offset);/* Deallocate any mapping for the region starting at ADDR and extending LEN bytes. Returns 0 if successful, -1 for errors (and sets errno). */extern int munmap (void *__addr, size_t __len) __THROW;/* Synchronize the region starting at ADDR and extending LEN bytes with the file it maps. Filesystem operations on a file being mapped are unpredictable before this is done. Flags are from the MS_* set. This function is a cancellation point and therefore not marked with __THROW. */extern int msync (void *__addr, size_t __len, int __flags); |
默认情况下,通过fork派生的子进程并不与其父进程共享内存区。
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 | #include "unpipc.h"#define SEM_NAME "mysem"int count = 0; // 计数器int main(int argc, char **argv){ int i, nloop; sem_t *mutex; if (argc != 2) err_quit("usage: incr1 <#loops>"); nloop = atoi(argv[1]); /* 4create, initialize, and unlink semaphore */ mutex = Sem_open(Px_ipc_name(SEM_NAME), O_CREAT | O_EXCL, FILE_MODE, 1); /** * sem_unlink() * removes the named semaphore referred to by name. * The semaphore name is removed immediately. * The semaphore is destroyed once all other processes that have the semaphore open close it. */ Sem_unlink(Px_ipc_name(SEM_NAME)); // 非缓冲模式,防止两个线程的输出交叉 // 父子线程共同访问一个信号量 // 由于mutex是2值信号量,相当于同步父子线程 // 所以实际上这里并不会发生交叉 setbuf(stdout, NULL); /* stdout is unbuffered */ if (Fork() == 0) /* child */ { for (i = 0; i < nloop; i++) { Sem_wait(mutex); printf("child: %d\n", count++); Sem_post(mutex); } exit(0); } /* 4parent */ for (i = 0; i < nloop; i++) { Sem_wait(mutex); printf("parent: %d\n", count++); Sem_post(mutex); } exit(0);} |
由于子进程为父进程的拷贝,所以子进程自己有一个count的副本,所以父子进程操作自己的count。这里使用一个有名信号量来同步父子进程。
程序说明:

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 | #include "unpipc.h"#define SEM_NAME "mysem" // 有名信号量用于同步父子进程(加锁)int main(int argc, char **argv){ int fd, i, nloop, zero = 0; int *ptr; // 访问共享内存的指针 sem_t *mutex; if (argc != 3) err_quit("usage: incr2 <pathname> <#loops>"); nloop = atoi(argv[2]); /* 4open file, initialize to 0, map into memory */ fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE); Write(fd, &zero, sizeof(int)); // 向文件中写入一个int型的0 // ptr返回共享内存起始位置 ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 映射一个int型大小的共享内存 Close(fd); /* 4create, initialize, and unlink semaphore */ mutex = Sem_open(Px_ipc_name(SEM_NAME), O_CREAT | O_EXCL, FILE_MODE, 1); // 信号量 Sem_unlink(Px_ipc_name(SEM_NAME)); setbuf(stdout, NULL); /* stdout is unbuffered */ if (Fork() == 0) /* child */ { for (i = 0; i < nloop; i++) { Sem_wait(mutex); printf("child: %d\n", (*ptr)++); Sem_post(mutex); } exit(0); } /* 4parent */ for (i = 0; i < nloop; i++) { Sem_wait(mutex); printf("parent: %d\n", (*ptr)++); Sem_post(mutex); } exit(0);} |
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [dell@localhost shm]$ ./incr2 ./count.data 100parent: 0parent: 1parent: 2parent: 3....child: 197child: 198child: 199[dell@localhost shm]$ ll count.data -rw-r--r--. 1 dell dell 4 8月 18 14:28 count.data[dell@localhost shm]$ file count.data count.data: data[dell@localhost shm]$ hexdump -d count.data 0000000 00200 00000 0000004[dell@localhost shm]$ |
注意:这里的count.data文件类型data类型,需用od、xxd、hexdump等命令才能查看。
上面3中的信号量为有名信号量,其具体实现由Posix决定,但是至少是内核持续性的。这里将其改为基于内存的信号量,并将其放置在共享内存中。

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 | #include "unpipc.h"struct shared{ sem_t mutex; /* the mutex: a Posix memory-based semaphore */ // 匿名信号量 int count; /* and the counter */} shared;int main(int argc, char **argv){ int fd, i, nloop; struct shared *ptr; if (argc != 3) err_quit("usage: incr3 <pathname> <#loops>"); nloop = atoi(argv[2]); /* 4open file, initialize to 0, map into memory */ fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE); Write(fd, &shared, sizeof(struct shared)); ptr = Mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); Close(fd); /* 4initialize semaphore that is shared between processes */ Sem_init(&ptr->mutex, 1, 1); // 初始化匿名信号量,设置为进程共享,初始值为1 setbuf(stdout, NULL); /* stdout is unbuffered */ if (Fork() == 0) /* child */ { for (i = 0; i < nloop; i++) { Sem_wait(&ptr->mutex); printf("child: %d\n", ptr->count++); Sem_post(&ptr->mutex); } exit(0); } /* 4parent */ for (i = 0; i < nloop; i++) { Sem_wait(&ptr->mutex); printf("parent: %d\n", ptr->count++); Sem_post(&ptr->mutex); } exit(0);} |
标签:
原文地址:http://www.cnblogs.com/fengkang1008/p/4739393.html