标签:
本文主要实现一个基于共享内存的计数器,通过父子进程对其访问。
本文程序需基于<<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 100 parent: 0 parent: 1 parent: 2 parent: 3 .... child: 197 child: 198 child: 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