首先让我们复习一下信号量是如何作为一个同步机制工作的。一般的信号量也被叫做一个计数信号量,因为带有一个可以增加的值(通常初始化为 0)。考虑一家租用自行车的商店,在它的库存中有 100 辆自行车,还有一个供职员用于租赁的程序。每当一辆自行车被租出去,信号量就增加 1;当一辆自行车被还回来,信号量就减 1。在信号量的值为 100 之前都还可以进行租赁业务,但如果等于 100 时,就必须停止业务,直到至少有一辆自行车被还回来,从而信号量减为 99。
二元信号量是一个特例,它只有两个值:0 和 1。在这种情况下,信号量的表现为互斥量(一个互斥的构造)。下面的共享内存示例将把信号量用作互斥量。当信号量的值为 0 时,只有 memwriter 可以获取共享内存,在写操作完成后,这个进程将增加信号量的值,从而允许 memreader 来读取共享内存。
示例 3. memwriter 进程的源程序
/** Compilation: gcc -o memwriter memwriter.c -lrt -lpthread **/ #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <semaphore.h> #include <string.h> #include "shmem.h" -
void report_and_exit(const char* msg) { [perror][4](msg); [exit][5](-1); } -
int main() { int fd = shm_open(BackingFile, /* name from smem.h */ O_RDWR | O_CREAT, /* read/write, create if needed */ AccessPerms); /* access permissions (0644) */ if (fd < 0) report_and_exit("Can't open shared mem segment..."); -
ftruncate(fd, ByteSize); /* get the bytes */ -
caddr_t memptr = mmap(NULL, /* let system pick where to put segment */ ByteSize, /* how many bytes */ PROT_READ | PROT_WRITE, /* access protections */ MAP_SHARED, /* mapping visible to other processes */ fd, /* file descriptor */ 0); /* offset: start at 1st byte */ if ((caddr_t) -1 == memptr) report_and_exit("Can't get segment..."); -
[fprintf][7](stderr, "shared mem address: %p [0..%d]\n", memptr, ByteSize - 1); [fprintf][7](stderr, "backing file: /dev/shm%s\n", BackingFile ); -
/* semahore code to lock the shared mem */ sem_t* semptr = sem_open(SemaphoreName, /* name */ O_CREAT, /* create the semaphore */ AccessPerms, /* protection perms */ 0); /* initial value */ if (semptr == (void*) -1) report_and_exit("sem_open"); -
[strcpy][8](memptr, MemContents); /* copy some ASCII bytes to the segment */ -
/* increment the semaphore so that memreader can read */ if (sem_post(semptr) < 0) report_and_exit("sem_post"); -
sleep(12); /* give reader a chance */ -
/* clean up */ munmap(memptr, ByteSize); /* unmap the storage */ close(fd); sem_close(semptr); shm_unlink(BackingFile); /* unlink from the backing file */ return 0; }
下面是 memwriter 和 memreader 程序如何通过共享内存来通信的一个总结:
-
上面展示的 memwriter 程序调用 shm_open 函数来得到作为系统协调共享内存的备份文件的文件描述符。此时,并没有内存被分配。接下来调用的是令人误解的名为 ftruncate 的函数
ftruncate(fd, ByteSize); /* get the bytes */
(编辑:ASP站长网)
|