进程间共享数据技术是每个操作系统都具有的特性,而每个操作系统都会略有不同,而思路方面都是一致的。经过整理,各操作系统进程间共享数据技术存在以下四种方法
1:管道数据
2:Socket数据
3:共享内存
4:文件方式
之
前广州某项目曾经考虑过使用管道实现,当然后来考虑到压力并不是很大,就改用文件方式处理了。Socket数据就比较直接了,同正常的网络socket一
致。共享内存技术是本文的一个重点介绍的内容。文件方式不外乎直接性质的文件写读操作,或者通过数据库的方式进行读写。
本文就Linux下面共享内存技术进行探讨,因为共享内存是进程间共享数据最快的方式。
Linux共享内存有两种模式(见参考文献 1,2):
mmap方法和shm方式。
这里具体说一下shm方式:
要使用共享内存,应该有如下步骤(见参考文献3):
引用
1.开辟一块共享内存 shmget()
2.允许本进程使用共某块共享内存 shmat()
3.写入/读出
4.禁止本进程使用这块共享内存 shmdt()
5.删除这块共享内存 shmctl()或者命令行下ipcrm
参考文献三中提到在使用shm方式的一些注意事项:
1:在使用 函数shmget的时候有一个key_t参数,我们可以使用
1. hmkey = ftok( "mcut" , 'a' ); // 计算标识符
hmkey = ftok( "mcut" , 'a' ); // 计算标识符
生成shmkey参数。
使用shm方式共享内存需要用到如下头文件:
1. #include <sys/types.h>
2. #include <sys/ipc.h>
3. #include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
相关函数:
1. int shmget( key_t shmkey , int shmsiz , int flag );
2. void *shmat( int shmid , char *shmaddr , int shmflag );
3. int shmdt( char *shmaddr );
int shmget( key_t shmkey , int shmsiz , int flag );
void *shmat( int shmid , char *shmaddr , int shmflag );
int shmdt( char *shmaddr );
参考文献四《共享内存的系统调用》提到:
例1. 创建关键字为0x1234,访问权限为0666,占用空间10K的共享内存,如果已存在则返回其标识号。
view plainprint?
1. int shmid;
2. shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT);
int shmid;
shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT);
例2. 创建关键字为0x1234,访问权限为0666,占用空间10K的共享内存,如果已存在则报错。
view plainprint?
1. int shmid;
2. shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT|IPC_EXCL);
int shmid;
shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT|IPC_EXCL);
例3. 将创建关键字为0x1234,占用空间10K的共享内存,链接到进程中。
view plainprint?
1. int shmid;
2. char *pmat;
3. shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT);
4. pmat = shmat(shmid, 0, 0);
int shmid;
char *pmat;
shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT);
pmat = shmat(shmid, 0, 0);
例4. 释放进程中地址paddr处的共享内存映射。
view plainprint?
1. char *paddr;
2. int ret;
3. ret = shmdt(paddr);
char *paddr;
int ret;
ret = shmdt(paddr);
经过整理:可以写出如下类代码:
view plainprint?
1. class TShareMemory{
2. public:
3. char *name,int size);
4. ~TShareMemory();
5. int Write(char *buffer);
6. char *Read(int size);
7. int GetID(void){
8. return segid;
9. }
10. private:
11. char *name;
12. int size;
13. int segid;
14. };
class TShareMemory{
public:
TShareMemory(char *name,int size);
~TShareMemory();
int Write(char *buffer);
char *Read(int size);
int GetID(void){
return segid;
}
private:
char *name;
int size;
int segid;
};
当然要完善,还要加上锁机制之类的。
在经典数据Unix网络编程卷二中有如下例子非常详细明显的使用信号量来互斥进程间数据的程序,本文根据连接 http://blog.chinaunix.net/u/22935/showart_298945.html 摘录如下:
1. /*server.c服务器程序*/
2. #include <sys/sem.h>
3. #include <fcntl.h>
4. #include <unistd.h>
5. #include <errno.h>
6. #include <sys/types.h>
7. #include <sys/ipc.h>
8. #include <sys/shm.h>
9. #include <stdio.h>
10.
11. union semun{
12. int val;
13. struct semid_ds *buf;
14. unsigned short int *array;
15. };
16.
17. main(int argc,char **argv)
18. {
19. int i,shm_id,sem_id,oflag;
20. int value;
21. char *ptr;
22. struct sembuf lock_it;
23. union semun options;
24.
25. oflag=0644|IPC_CREAT;
26. if(argc!=2)
27. {
28. printf(“usage:server <pathname>\n”);
29. exit(1);
30. }
31. if((sem_id=semget(ftok(argv[1],0),100,oflag))<0)/*创建信号量*/
32. perror(“shmget”);
33. options.val=1;
34. semctl(sem_id,0,SETVAL,options);/*设置信号量值*/
35. if((shm_id=shmget(ftok(argv[1],0),100,oflag))<0)/*创建共享内存区*/
36. perror(“shmget”);
37. if((ptr=shmat(shm_id,NULL,0))<0)/*连接到共享内存区*/
38. perror(“shmat”);
39.
40. while(1)
41. {
42. if((strcmp(ptr,”\0”))==0)/*如果共享内存区没有数据,则等待*/
43. {
44. continue;
45. }
46. else
47. {
48. if((strcmp(ptr,”q\n”))==0)/*如果数据为”q\n”突出循环*/
49. break;
50. lock_it.sem_num=0;
51. lock_it.sem_op=-1;
52. lock_it.sem_flg=IPC_NOWAIT;
53. /*信号量减一*/
54. /*读出共享内存区内容*/
55. /*把共享内存区清0*/
56. lock_it.sem_num=0;
57. lock_it.sem_op=1;
58. lock_it.sem_flg=IPC_NOWAIT;
59. /*信号量加一*/
60. }
61. }
62. semctl(sem_id,IPC_RMID,0);
63. shmctl(shm_id,IPC_RMID,0);
64. exit(0);
65. }
/*server.c服务器程序*/
#include <sys/sem.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
union semun{
int val;
struct semid_ds *buf;
unsigned short int *array;
};
main(int argc,char **argv)
{
int i,shm_id,sem_id,oflag;
int value;
char *ptr;
struct sembuf lock_it;
union semun options;
oflag=0644|IPC_CREAT;
if(argc!=2)
{
printf(“usage:server <pathname>\n”);
exit(1);
}
if((sem_id=semget(ftok(argv[1],0),100,oflag))<0)/*创建信号量*/
perror(“shmget”);
options.val=1;
semctl(sem_id,0,SETVAL,options);/*设置信号量值*/
if((shm_id=shmget(ftok(argv[1],0),100,oflag))<0)/*创建共享内存区*/
perror(“shmget”);
if((ptr=shmat(shm_id,NULL,0))<0)/*连接到共享内存区*/
perror(“shmat”);
while(1)
{
if((strcmp(ptr,”\0”))==0)/*如果共享内存区没有数据,则等待*/
{
continue;
}
else
{
if((strcmp(ptr,”q\n”))==0)/*如果数据为”q\n”突出循环*/
break;
lock_it.sem_num=0;
lock_it.sem_op=-1;
lock_it.sem_flg=IPC_NOWAIT;
semop(sem_id,&lock_it,1);/*信号量减一*/
printf(“server:%s”,ptr);/*读出共享内存区内容*/
strcpy(ptr,”\0”);/*把共享内存区清0*/
lock_it.sem_num=0;
lock_it.sem_op=1;
lock_it.sem_flg=IPC_NOWAIT;
semop(sem_id,&lock_it,1);/*信号量加一*/
}
}
semctl(sem_id,IPC_RMID,0);
shmctl(shm_id,IPC_RMID,0);
exit(0);
}
客户端程序:
1. /*user.c用户程序*/
2. #include <sys/sem.h>
3. #include <fcntl.h>
4. #include <unistd.h>
5. #include <errno.h>
6. #include <sys/types.h>
7. #include <sys/ipc.h>
8. #include <sys/shm.h>
9. #include <stdio.h>
10.
11. union semun{
12. int val;
13. struct semid_ds *buf;
14. unsigned short int *array;
15. };
16.
17. main(int argc,char **argv)
18. {
19. int i,shm_id,sem_id;
20. int value;
21. char *ptr;
22. struct sembuf lock_it;
23. union semun options;
24.
25. if(argc!=2)
26. {
27. printf(“usage:server <pathname>\n”);
28. exit(1);
29. }
30. if((sem_id=semget(ftok(argv[1],0),0,0))<0)/*打开信号量*/
31. perror(“shmget”);
32. if((shm_id=shmget(ftok(argv[1],0),0,0))<0)/*打开共享内存区*/
33. perror(“shmget”);
34. if((ptr=shmat(shm_id,NULL,0))<0)/*连接共享内存区*/
35. perror(“shmat”);
36.
37. while(1)
38. {
39. lock_it.sem_num=0;
40. lock_it.sem_op=-1;
41. lock_it.sem_flg=IPC_NOWAIT;
42. /*信号量减一*/
43. fgets(ptr,10,stdin);/*从键盘读入数据到共享内存区*/
44. printf(“user:%s”,ptr);
45. if((strcmp(ptr,”q\n”))==0)
46. exit(0);
47. lock_it.sem_num=0;
48. lock_it.sem_op=1;
49. lock_it.sem_flg=IPC_NOWAIT;
50. /*信号量加一*/
51. }
52. exit(0);
53. }
/*user.c用户程序*/
#include <sys/sem.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
union semun{
int val;
struct semid_ds *buf;
unsigned short int *array;
};
main(int argc,char **argv)
{
int i,shm_id,sem_id;
int value;
char *ptr;
struct sembuf lock_it;
union semun options;
if(argc!=2)
{
printf(“usage:server <pathname>\n”);
exit(1);
}
if((sem_id=semget(ftok(argv[1],0),0,0))<0)/*打开信号量*/
perror(“shmget”);
if((shm_id=shmget(ftok(argv[1],0),0,0))<0)/*打开共享内存区*/
perror(“shmget”);
if((ptr=shmat(shm_id,NULL,0))<0)/*连接共享内存区*/
perror(“shmat”);
while(1)
{
lock_it.sem_num=0;
lock_it.sem_op=-1;
lock_it.sem_flg=IPC_NOWAIT;
semop(sem_id,&lock_it,1);/*信号量减一*/
fgets(ptr,10,stdin);/*从键盘读入数据到共享内存区*/
printf(“user:%s”,ptr);
if((strcmp(ptr,”q\n”))==0)
exit(0);
lock_it.sem_num=0;
lock_it.sem_op=1;
lock_it.sem_flg=IPC_NOWAIT;
semop(sem_id,&lock_it,1);/*信号量加一*/
}
exit(0);
}
程序开辟共享内存后,容易造成一些问题就是下次创建的时候会报错17,表示EEXIST.
可以使用以下方法进行删除:
- ipcs -m
ipcs -m
获取到该共享内存的ID,然后删除ipc
- ipcrm -m 上面获取到的ID