mmap (C, Python exchange data)
毎度のことだけど、ほぼ個人的メモなので、もし参考にする人がいたら注意してね!!
意外と見てくれている人がいるみたいなので。
Linuxなどまともに触れたことがなく、OSと言ってもFreeRTOS程度のものしかいじったことがなかった。。。
RaspberryPiで遊んでいたときに、"PythonのプログラムとCのプログラムで変数を共有できたら楽なのになぁ"という問題に直面した。
いろいろ調べた結果mmapという関数(機能)を使えば、イメージした動作が実現できそうだ。
CとPythonの両方から一つのファイル(メモリ)をリードライトすると何となく危険な気がしたので、今回はPythonからCへ情報を提供するファイルtoc.datとCからPythonへ情報を提供するファイルtopy.datの二つを使って実験してみた。。。
まずはPython側
#---- Cにデータを提供するファイルについて ---- toC_File = open(toc.dat, 'r+') toC_No = toC_File.fileno() #ここのlengthは重要で、ファイルサイズの値と一致させないといけない toC_Map = mmap.mmap(toC_No,length,access=mmap.ACCESS_WRITE) toC_File.seek(0) write_str = "0123456789" print len(write_str) #書き込む文字列長をコンソール上に表示して確認してみる toC_Map.write(write_str) toC_File.close() #---- Cからデータをもらうファイルについて ---- toPy_File = open(topy.dat,'r') #ここのdatasizeも重要。ファイルサイズの値と一致させないといけない toPy_Map = mmap.mmap(toPy_File.fileno(), datasize, access=mmap.ACCESS_READ) toPy_File.seek(0) # 想定したデータがやり取りできているか確認するためにはreadして中身をみるといい param = toPy_Map.read(3) #print param toPy_File.close()
そしてC側
int topy_fd, toc_fd; long topy_size, topy_pagesize, toc_size, toc_pagesize; char *topy_pc, *toc_pc; // topy.dat用データポインタとtoc.dat用データポインタ // 想定されるデータ量を保持したファイルをもともと作っておくと良さげ // 今回はその部分は省略 if((topy_fd=open(topy.dat,O_RDWR|O_CREAT,0666))==-1) { perror("open"); exit(-1); } topy_pagesize=sysconf(_SC_PAGE_SIZE); // DATASIZEはpythonで使ったdatasizeと同じ値で、必要最低限が良さそう。 topy_size=(DATASIZE*sizeof(char)/topy_pagesize+1)*topy_pagesize; if(lseek(topy_fd,0,SEEK_SET) < 0){ perror("lseek"); exit(-1); } topy_pc=(char*)mmap(0,topy_size,PROT_READ|PROT_WRITE,MAP_SHARED,topy_fd,0); if((int)topy_pc == -1){ perror("mmap"); exit(-1); } // あとはtopy_pcを使って値を入れていけばOK.python側で参照できるはず。 close(topy_fd); //---------------------------------------------------- if((toc_fd=open(toc.dat,O_RDWR))== -1){ perror("open"); exit(-1); } toc_pagesize=sysconf(_SC_PAGE_SIZE); // ここのLENGTHはpythonで使ったlengthと同じ値で、必要最低限が良さそう。 toc_size=(LENGTH*sizeof(char)/toc_pagesize+1)*toc_pagesize; if(lseek(toc_fd,0,SEEK_SET)<0){ perror("lseek"); exit(-1); } toc_pc=(char*)mmap(0,toc_size,PROT_READ,MAP_SHARED,toc_fd,0); if ( toc_pc == MAP_FAILED ) { printf("Mmap Error!!\n"); } // あとはtoc_pcを使ってpythonからのデータを確認すればOK. close(toc_fd);
topy_pcとtoc_pcのポインタをグローバルにしていろいろいじってデータのやりとりをすると思いのほかうまくいった。常時走らせるプログラムでない場合はmunmapとかをうまく使ってやったほうが良さげ。