标签:
写 Linux Server 端程序,必然会涉及到进程间通信 IPC. 通信必然伴随着同步机制,下面是一些常见的通信与同步机制:
Domain Socket
, 本机 TCP Socket
,文件对于大部分的业务场景,本机 TCP Socket
足以,现在Linux 也对本机 TCP Socket
做了很好的优化。而且如果以后需要分机器部署进程,那么程序不需要怎么改动,十分方便。至于 Domain Socket,应用也很广泛,可以看这篇文章:UNIX Domain Socket IPC。
用共享内存做IPC手段的最大优势是效率最高,缺点是需要借助其他同步机制 。
共享内存IPC的基本原理也很简单:把同一块物理内存映射到多个进程的虚拟地址空间,进程虚拟地址布局可以看这篇:Linux虚拟地址空间布局。Linux 在 <sys/shm.h>
提供了相关操作的接口:
key
创建或获取一个存在的共享内存对象;attach
, 关联到当前进程的虚拟地址空间;detach
, 从当前进程中分离;详细的函数接口说明可以看: Linux进程间通信——使用共享内存
下面的 demo 一个读,一个写,IPC采用共享内存,同步就用最简单的条件变量配合。最终实现在一个进程读标准输入,另外一个进程输出到控制台。
可以使用 ipcs -m
查看系统使用的共享内存 IPC资源列表。
公共头文件:
/* file: shm_comm.h */
#ifndef _SHM_COMM_H
#define _SHM_COMM_H
#define MY_SHM_KEY 0x12
#define READ_SHM 1
#define WRITE_SHM -1
typedef struct {
int flag;
char buff[1020];
}__attribute__((packed)) S_SHM_BUF; // 单字节对齐,方便 ipcs -m 查看对比大小
#endif
读进程
/* file:shm_read.c */
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include "shm_comm.h"
int main()
{
void *shm = NULL;
S_SHM_BUF *shbuf;
int ret = 0;
int shmid = 0;
/* 由 key 申请共享内存, 得到 id */
shmid = shmget(MY_SHM_KEY, sizeof(S_SHM_BUF), IPC_CREAT);
if (-1 == shmid) {
printf("get share memory failed!\n");
exit(EXIT_FAILURE);
}
/* 根据 id 把共享内存 attach 到进程地址空间,得到首地址 */
shm = shmat(shmid, 0, 0);
if (-1L == (long)shm) {
printf("share memory attach failed!\n");
}
printf("share memory attached at %p\n", shm);
shbuf = (S_SHM_BUF*)shm;
while (1) {
if (READ_SHM == shbuf->flag) {
printf("read: %s\n", shbuf->buff);
shbuf->flag = WRITE_SHM;
if (0 == strncmp(shbuf->buff, "end", 3)) {
break;
}
} else {
sleep(1);
}
}
/* 根据首地址,把共享内存从进程空间 detach 掉 */
ret = shmdt(shm);
if (-1 == ret) {
printf("share memory detach failed!\n");
exit(EXIT_FAILURE);
}
/* 根据id,让操作系统删掉共享内存 */
ret = shmctl(shmid, IPC_RMID, 0);
if (-1 == ret) {
printf("share memory remove failed!\n");
exit(EXIT_FAILURE);
}
printf("program end ok!\n");
return 0;
}
写进程
/* file: shm_write.c */
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include "shm_comm.h"
int main()
{
void *shm = NULL;
S_SHM_BUF *shbuf;
int ret = 0;
int shmid = 0;
shmid = shmget(MY_SHM_KEY, sizeof(S_SHM_BUF), IPC_CREAT);
if (-1 == shmid) {
printf("get share memory failed!\n");
exit(EXIT_FAILURE);
}
shm = shmat(shmid, 0, 0);
if (-1L == (long)shm) {
printf("share memory attach failed!\n");
}
printf("share memory attached at %p\n", shm);
shbuf = (S_SHM_BUF*)shm;
memset(shbuf, 0, sizeof(*shbuf));
shbuf->flag = WRITE_SHM;
while (1) {
if (WRITE_SHM == shbuf->flag) {
printf("write: ");
scanf("%s", shbuf->buff);
shbuf->flag = READ_SHM;
if (0 == strncmp(shbuf->buff, "end", 3)) {
break;
}
} else {
sleep(1);
}
}
ret = shmdt(shm);
if (-1 == ret) {
printf("share memory detach failed!\n");
exit(EXIT_FAILURE);
}
printf("program end ok!\n");
return 0;
}
Makefile
# Makefile
CFLAGS = -Wall -Werror -g -m64
compile = $(CC) $(CFLAGS) $^ -o $@
.PHONY : all
all : shm_read.bin shm_write.bin
# 注意 makefile 的缩进要用<TAB>
shm_read.bin : shm_read.c shm_comm.h
$(compile)
shm_write.bin : shm_write.c shm_comm.h
$(compile)
.PHONY : clean
clean:
rm *.bin
标签:
原文地址:http://blog.csdn.net/thisinnocence/article/details/51348478