使用Posix共享内存区实现进程间通信
使用Posix共享内存区实现进程间通信
使用Posix共享内存区通常涉以下步骤:
- 进程A 调用shm_open 创建共享内存区
- 进程A调用ftruncate修改共享内存区大小
- 进程A 调用mmap将共享内存区映射到进程地址空间ptrA
- 进程A 使用ptrA对共享内存区进程更改
- 进程B 使用shm_open打开已有共享内存区
- 进程B 调用fstat获取共享内存区大小
- 进程B 调用mmap将共享内存区映射到进程地址空间ptrB
- 进程B 使用ptrB对共享内存区进行更改
- 最后由进程A/B调用shm_unlink删除共享内存区
1、shm_open 创建/打开共享内存区
shm_open调用成功后返回共享内存区的文件描述符, 并在/dev/shm目录下生成相应的文件。
shm_open函数声明包含在文件 sys/mman.h 中;
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
int shm_open(const char *name, int oflag, mode_t mode);
oflag的值包含在文件 fcntl.h中
#define O_RDONLY 00 //只读
#define O_WRONLY 01 //只写
#define O_RDWR 02 //可读可写
#define O_CREAT 0100 //创建
#define O_EXCL 0200 //如果共享内存区已存在则返错误
mode的值包含在文件sys/stat.h中
#define S_IRUSR __S_IREAD /* Read by owner. */
#define S_IWUSR __S_IWRITE /* Write by owner. */
#define S_IXUSR __S_IEXEC /* Execute by owner. */
#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
#define S_IROTH (S_IRGRP >> 3) /* Read by others. */
#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
2、ftruncate修改内存区大小
ftruncate包含在头文件unistd.h中
/* Truncate the file FD is open on to LENGTH bytes. */
int ftruncate (int __fd, __off_t __length)
fd:shm_ope返回的描述符
length:共享内存区的大小
3、fstat获取文件大小
fstat包含在头文件sys/stat.h中
在打开已存在的共享内存区时,可以用fstat获取共享内存区的大小。
/* Get file attributes for the file, device, pipe, or socket
that file descriptor FD is open on and put them in BUF. */
int fstat (int __fd, struct stat *__buf)
fd:shm_open返回的描述符
stat.st_size是共享内存区的大小
4、mmap将共享内存区映射到进程地址空间
mmap包含在头文件mman.h中
void *mmap (void *__addr, size_t __len, int __prot,
int __flags, int __fd, __off_t __offset)
参数
__addr: 映射到进程的地址,直接传入NULL就行。
__len: 共享内存区的大小。
__prot: 权限
PROT_READ 可读
PROT_WRITE 可写
PROT_EXEC 可执行
__flags:映射方式
MAP_SHARED: 当前进程所做的修改其他进程可见
MAP_PRIVATE:当前进程所做的修改其他进程不可见
__fd: shm_open返回的描述符
__offset:偏移量,一般都传入0
5、shm_unlink删除共享内存区
shm_unlink和shm_open在同一文件中,用于删除共享内存区。
/* Remove shared memory segment. */
int shm_unlink (const char *__name);
6、练习
- 进程shmserver创建共享内存区shmtest,并创建子进程等待其他进程向shmtest中写入数据。
- 进程shmcli向共享内存区shmtest写入数据,并给进程shmserver发送信号。
- 进程shmserver取出共享内存区shmtest中的数据并输出到窗口。
cond_h.h
#define COUNT 10
typedef struct shm_block
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int arr[COUNT];
int nput;
int nread;
int ncount;
}shm_block;
void shm_block_init(shm_block* shm)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&shm->mutex, &attr);
pthread_mutexattr_destroy(&attr);
pthread_condattr_t cond_attr;
pthread_condattr_init(&cond_attr);
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&shm->cond, &cond_attr);
pthread_condattr_destroy(&cond_attr);
bzero(shm->arr, sizeof(shm->arr));
shm->ncount = 0;
shm->nput = 0;
shm->nread = 0;
}
shm_server.c
#include<unistd.h>
#include<pthread.h>
#include<mqueue.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<strings.h>
#include<wait.h>
#include"cond_h.h"
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("shmcreate [shmname]\n");
return 0;
}
shm_block shm;
shm_block_init(&shm);
int shmfd = shm_open(argv[1], O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
if (shmfd == -1)
{
printf("%d : %s\n",__LINE__, strerror(errno));
return -1;
}
printf("create shared memory %s. \n", argv[1]);
if (ftruncate(shmfd, sizeof(shm_block)) < 0)
{
printf("%d : %s\n",__LINE__, strerror(errno));
return -1;
}
shm_block* pBlock = (shm_block*)mmap(NULL, sizeof(shm_block), PROT_WRITE|PROT_READ, MAP_SHARED, shmfd, 0);
if (NULL == pBlock)
{
printf("%d : %s\n",__LINE__, strerror(errno));
return -1;
}
close(shmfd);
memcpy(pBlock, &shm, sizeof(shm));
int pid = fork();
if (pid == 0)
{
int fd = shm_open(argv[1], O_RDWR, S_IRUSR|S_IWUSR);
if (fd < 0)
{
printf("%d : %s\n",__LINE__, strerror(errno));
return -1;
}
struct stat st;
fstat(fd, &st);
printf("%d: st_size = %d\n", __LINE__, st.st_size);
shm_block *p = (shm_block*)mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (NULL == p)
{
printf("%d : %s\n",__LINE__, strerror(errno));
return -1;
}
while (1)
{
pthread_mutex_lock(&p->mutex);
while (p->ncount <= 0)
pthread_cond_wait(&p->cond, &p->mutex);
int value = p->arr[p->nread];
p->ncount--;
p->nread++;
p->nread %= COUNT;
pthread_mutex_unlock(&p->mutex);
printf("%d: p->nread:%d, arr[nread] : %d\n",__LINE__, p->nread, value);
}
munmap(p, st.st_size);
close(fd);
return 0;
}
int stat_loc = 0;
waitpid(pid, &stat_loc, 0);
munmap(pBlock, sizeof(shm));
if (WIFEXITED(stat_loc))
printf("Child process exited with status: %d\n", WEXITSTATUS(stat_loc));
return 0;
}
shm_cli.c
#include<sys/mman.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include"cond_h.h"
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("cond_put <shmname> <value>");
return -1;
}
char *shmname = argv[1];
int value = atoi(argv[2]);
int shmfd = shm_open(shmname, O_RDWR, 0);
if (-1 == shmfd)
{
printf("%d: %s\n", __LINE__, strerror(errno));
return -1;
}
shm_block* p = (shm_block*)mmap(NULL, sizeof(shm_block), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
if (NULL == p)
{
printf("%d: %s\n", __LINE__, strerror(errno));
return -1;
}
close(shmfd);
pthread_mutex_lock(&p->mutex);
do
{
if (p->ncount == COUNT)
break;
p->arr[p->nput] = value;
printf("count: %d, nput: %d, nread: %d,arr[nput]:%d\n", p->ncount, p->nput, p->nread,value);
p->nput = (p->nput + 1) % COUNT;
p->ncount++;
if (p->ncount == 1)
pthread_cond_signal(&p->cond);
} while (0);
pthread_mutex_unlock(&p->mutex);
close(shmfd);
return 0;
}
使用方法:
unlink /dev/shm/shmtest
gcc shm_server.c -lrt -lpthread -o shmserver
./shmserver shmtest
gcc shm_cli.c -lrt -lpthread -o shmcli
./shmcli shmtest 33
./shmcli shmtest 34
./shmcli shmtest 35
shmserver输出:
create shared memory shmtest.
60: st_size = 144
83: p->nread:1, arr[nread] : 33
83: p->nread:2, arr[nread] : 34
83: p->nread:3, arr[nread] : 35