一、基础代码API使用例程:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/shm.h> 4 /*************基本的函数API******************** 5 共享内存函数API 6 int shmget(key_t key, int size, int flag) 7 key: 8 共享内存的键值,多个进程可以通过它访问同一个共享内存。常用特殊值:IPC_PRIVATE,创建当前进程的私有共享内存 9 size: 10 指定创建共享内存的大小 11 flag: 12 操作权限 13 char * shmat(int shm_id, const void * addr, int flag) 14 shm_id: 15 要映射的共享内存标识符 16 addr: 17 指定在调用进程中映射共享内存的地址。通常取值为0,表示由系统自动分配地址。 18 flag: 19 设置共享内存的操作权限。若取值为0,表示可对共享内存进行读写操作。 20 int shmctl(int shm_id, int cmd, struct shmid_ds * buf) 21 shm_id: 22 共享内存标识符 23 cmd: 24 指定索要进行的操作:IPC_STAT IPC_SET IPC_RMID SHM_LOCK SHM_UNLOCK 25 buf: 26 结构体型指针 27 int shmdt(const void * addr) 28 **********************************************/ 29 #define Test_pipe 0 30 #define Test_Shmget 0 31 #define Test_AT_w 0 32 #define Test_AT_r 0 33 #define Test_DT 1 34 int main(int argc, char *argv[]) 35 { 36 #if Test_pipe 37 int x,fd[2]; 38 char buf[30],s[30]; 39 pipe(fd); 40 x = fork(); 41 if(0 == x) 42 { 43 sprintf(buf,"This is an pipe!"); 44 write(fd[1],buf,30); 45 exit(0); 46 } 47 else 48 { 49 wait(0); 50 read(fd[0],s,30); 51 printf("read: %s\n",s); 52 } 53 #endif 54 55 #if Test_Shmget 56 int shm_id; 57 shm_id = shmget(IPC_PRIVATE,4096,0666); 58 if(shm_id < 0) 59 { 60 perror("shmget id < 0"); 61 exit(0); 62 } 63 printf("成功建立共享内存区域: %d\n",shm_id); 64 system("ipcs -m"); 65 #endif 66 67 #if Test_AT_w 68 int shm_id; 69 char *shm_buf; 70 shm_id = atoi(argv[1]); 71 shm_buf = shmat(shm_id,0,0); 72 printf("写如数据到共享内存:\n"); 73 sprintf(shm_buf,"对共享内存的读写操作!"); 74 printf("%s\n",shm_buf); 75 #endif 76 77 #if Test_AT_r 78 int shm_id; 79 char *shm_buf,str; 80 shm_id = atoi(argv[1]); 81 shm_buf = shmat(shm_id,0,0); 82 printf("写如数据到共享内存:\n"); 83 sprintf(str,shm_buf); 84 printf("%s\n",str); 85 system("ipcs -m"); 86 #endif 87 88 #if Test_DT 89 int shm_id; 90 char *shm_buf; 91 shm_id = atoi(argv[1]); 92 shm_buf = shmat(shm_id,0,0); 93 shmdt(shm_buf); 94 shmctl(shm_id,IPC_RMID,NULL); 95 system("ipcs -m"); 96 #endif 97 }
二、接口详细介绍
三、基础实例
1)IPC通讯中共享内存参看代码:
Client端代码client.c(gcc client.c -lm -o client)
shmget函数得到的共享内存的大小有参数确定,参数的单位是Byte!
同样的shmget参数的0666代表的内容是,共享内存空间的可读可写性!
使用ftok函数获取的key_t key的作用在于生成一个文件节点引索,这样才能够连接两个进程让他们以这个引索值作为标识ID!
shmdt函数用来删除释放掉创建的共享内存空间!
shmat函数用来映射已经创建好的虚拟内存空间地址!返回值为两个进程进行操作的共享内存起始地址!
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <time.h> #include <math.h> #define random(x) (rand()%x) #define PI 3.1415926 #define Width 20 #define Height 20 int main(int argc,char *argv[]) { key_t key = 0; int shmid = 0; setbuf(stdout,NULL); printf("Begin to Create the shared-mem...\n"); key = ftok(".",2); // Get the only IPC ID:inode'num + 1 if(key<0) { perror("ftok"); return -1; } printf("key=%d\n",key); sleep(1); printf("...\n"); printf("%d\n",IPC_CREAT); shmid = shmget(key,100,IPC_EXCL | IPC_CREAT | 0666); // Get shared mem:IPC_ID_key Mem_size if(shmid<0) { perror("shmget"); return -2; } char * shared_mem_addr = shmat(shmid,NULL,0); // mapping the mem_addr to the addr of the Process printf("...\n"); sleep(2); // waitting for setup the mem printf("The shared-mem create sucessfully!\n"); printf("Begin to insert the data into shared-mem!\n"); int i=0; while(i<Width*Height) { *(shared_mem_addr+i) = 200*sin((double)i*PI/180.0);// random(255)+255; usleep(100); printf("."); i++; } printf("\nThe data insert finish!\n"); shmdt(shared_mem_addr); return 0; }
Server端代码server.c(gcc server.c -o server)
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <time.h> #define Width 20 #define Height 20 int main(int argc,char *argv[]) { key_t key = 0; int shmid = 0; key = ftok(".",2); // Get the only IPC ID:inode'num + 1 if(key<0) { perror("ftok"); return -1; } shmid = shmget(key,100,IPC_CREAT | 0666); // Get shared mem:IPC_ID_key Mem_size if(shmid<0) { perror("shmget"); return -2; } char * shared_mem_addr = shmat(shmid,NULL,0); // mapping the mem_addr to the addr of the Process sleep(2); int i=0; while(i<Width*Height) { printf("The image data:%d\n",*(shared_mem_addr+i)); usleep(100); i++; } shmdt(shared_mem_addr); sleep(1); shmctl(shmid,IPC_RMID,NULL); return 0; }
首先运行Clent端,然后再运行Server端即可!
2)Python与C语言共享内存实例
python内存共享:
from ctypes import * import numpy as np import codecs import datetime SHM_SIZE = 1024*1024*20 # 20MBytes SHM_KEY = 123559 OUTFILE="Shared.PNG" try: rt = CDLL('librt.so') except: rt = CDLL('librt.so.1') shmget = rt.shmget shmget.argtypes = [c_int, c_size_t, c_int] shmget.restype = c_int shmat = rt.shmat shmat.argtypes = [c_int, POINTER(c_void_p), c_int] shmat.restype = c_void_p shmid = shmget(SHM_KEY, SHM_SIZE, 0o666) if shmid < 0: print ("System not infected") else: addr = shmat(shmid, None, 0) f=open(OUTFILE, 'wb') begin_time = datetime.datetime.now() DataLength = int.from_bytes(string_at(addr,4), byteorder='little', signed=True) #这里数据文件是小端int16类型 ImgData = string_at(addr+4,DataLength) end_time = datetime.datetime.now() print(DataLength, ' Bytes') print('Type:',type(ImgData),' Bytes:', len(ImgData)) f.write(ImgData) f.close() #print ("Dumped %d bytes in %s" % (SHM_SIZE, OUTFILE)) print("Success!",end_time-begin_time)
C Transform:
#include <stdio.h> #include <stdlib.h> #include <sys/shm.h> #include <string.h> #include <time.h> #include <sys/time.h> #define SHAERD_MEM_SIZE 20 * 1024 * 1024 // 20MBytes char mem_free(void *ptr); time_t get_timestamp_ms(void); char *file_read(unsigned int *file_bytes, char *file_name); int main(int argc, char *argv[]) { int id = 0; size_t offset = 0; char *data = NULL; char *ImgData = NULL; unsigned int file_bytes = 0; time_t start_time, end_time; if (argc < 2) { printf("args too less\n"); return 0; } id = shmget(123559, SHAERD_MEM_SIZE, IPC_CREAT | 0777); if (id < 0) { printf("get id failed\n"); return 0; } data = shmat(id, NULL, 0); if (data == NULL) { printf("shamt failed\n"); return 0; } ImgData = file_read(&file_bytes, argv[1]); offset = sizeof(unsigned int); printf("Size of unsigned long:%d\n", offset); printf("Size of Image File:%d\n", file_bytes); start_time = get_timestamp_ms(); memcpy(data, &file_bytes, sizeof(unsigned int)); memcpy(data + offset, ImgData, file_bytes); end_time = get_timestamp_ms(); printf("Time Cost:%d\n", end_time - start_time); mem_free(ImgData); return 0; } char *file_read(unsigned int *file_bytes, char *file_name) { int file_size; FILE *fd = NULL; char *file_data = NULL; fd = fopen(file_name, "rw"); if(fd < 0) { printf("File open failed...\n"); return NULL; } fseek(fd, 0, SEEK_END); file_size = ftell (fd); file_data = malloc(sizeof(char)*file_size); if(file_data == NULL) { printf("Malloc failed...\n"); return NULL; } fseek(fd, 0, SEEK_SET); *file_bytes = fread(file_data,sizeof(char),file_size,fd); fclose(fd); return file_data; } time_t get_timestamp_ms(void) { time_t timestamp_ms = 0; struct timeval tv; gettimeofday(&tv,NULL); timestamp_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; return timestamp_ms; } char mem_free(void *ptr) { if(NULL != ptr) { free(ptr); return 0; } printf("Memory is Empty...\n"); return -1; }
python-c指针传递
import os import sys import time import ctypes from ctypes import * from ctypes import cdll BUFF_SIZE = 6*1024*1024 class POINT(Structure): # 定义了一个类,类当中的基本成员变量包括了x、y, 相当于C语言中的 struct POINT{int x;inty}; _fields_ = [("x", c_int),("y", c_int),("addr", POINTER(c_uint8))] DataPoint = (c_uint8 * 10)() # 定义一个大小为10指针实例作为缓存 DataPoint[3] = 22 point = POINT(10, 20, DataPoint) # 定义个类对象Obj, 相当于 struct POINT point={10,20}; print('Line', sys._getframe().f_lineno, ':', point.x, point.y, point.addr[3]) point = POINT(y=5) # 定义个类对象Obj, 相当于 struct POINT point={,20}; print('Line', sys._getframe().f_lineno, ':', point.x, point.y) TenPointsArrayType = POINT * 3 # 重定义了一个POINT数组类型,相当于C语言中的 #define TenPointsArrayType POINT*3 arr = TenPointsArrayType() for pt in arr: print(pt.x, pt.y, pt.addr) p = os.getcwd() + '/libfunc.so' # 获取当前的动态库的绝对路径位置 f = cdll.LoadLibrary(p) # 使用LoadLibrary接口加载C语言动态库 function = f.py_point_address # 从当前库当中取得clib中的函数py_point_address,并重命名为function function.argtypes = [POINTER(c_byte)] # 设置当前函数的输入参数 i = ctypes.c_int(42) # 定义一个整数类型的变量,变量初始值为 42,相当于C语言中的 int i=42; pi = ctypes.pointer(i) # 通过使用pointer接口获取,相当于C语言中的 int *pi = &i; print('Line', sys._getframe().f_lineno, ':', pi.contents) # 查看指针变量的信息 print('Line', sys._getframe().f_lineno, ':', pi[0]) # 查看指针所指向的内容,相当于C语言中的 *pi; a = (c_byte * BUFF_SIZE)() # 定义一个大小为BUFF_SIZE指针实例作为缓存 # cast(a, POINTER(c_uint8)) # 函数可以将一个指针实例强制转换为另一种 ctypes 类型 print('Line', sys._getframe().f_lineno, ':', a) print('Line', sys._getframe().f_lineno, ':', type(a)) time_start = time.time() function(a) # 执行function函数并传入a地址参数 time_end = time.time() for i in range(10): print(a[i]) print('Line', sys._getframe().f_lineno, ':', 'TimeCost:', (time_end - time_start)*1000, 'ms') # 记录当前函数调用消耗的时间 data = ctypes.c_uint8(10) # 定义一个整数类型的变量,变量初始值为 10,相当于C语言中的 char data=42; data_addr = ctypes.byref(data, 0) # 通过使用byref接口获取地址,相当于C语言中的 char *data_addr = &data; byref(obj, offset) 对应于这段 C 代码:(((char *)&obj) + offset) print('Line', sys._getframe().f_lineno, ':', type(data)) print('Line', sys._getframe().f_lineno, ':', type(data_addr)) value = 'hello world' # 定义一个字符串变量 address = id(value) # 获取value的地址,赋给address get_value = ctypes.cast(address, ctypes.py_object).value # 读取地址中的变量 print('Line', sys._getframe().f_lineno, ':', address, get_value) # res = f.func(99) # 普通函数调用 print('Line', sys._getframe().f_lineno, ':', res)
C:
#include <stdio.h> #include <sys/shm.h> #include <string.h> #include <stdlib.h> #define BUFF_SIZE 6*1024*1024 /* func.c */ int func(int a) { return a*a; } void cycle_calc(int b) { int count = 100; while(count--){ b*=2; printf("%d - %d\n", count, b); } } unsigned char * c_point_address(void) { unsigned char *Img = malloc(sizeof(unsigned char)*1000); printf("C-Address:%d\n", Img); memset(Img, 20, 1000); return Img; } int py_point_address(unsigned char * Addr) { unsigned char *Img = malloc(sizeof(unsigned char)*BUFF_SIZE); // printf("C-Address:%x\n", Img); // printf("Python-Address:%x\n", Addr); memset(Img, 20, BUFF_SIZE); memcpy((unsigned char * )Addr, Img, BUFF_SIZE); return 1; }
shell compile:
#!/bin/bash gcc -fPIC -shared function.c -o libfunc.so python3 MemoryTest.py
Reference:
https://www.cnblogs.com/mq0036/p/8492621.html
转载请注明出处!感谢GISPALAB实验室的老师和同学们的帮助和支持~