95773


mmapを使用して名前付きの共有メモリ(RAM)上でデータのやり取りをしたいと考えています。  
下記のプログラムを実行して読み出すと全て0になっており、期待値としては、書き込んだ(128, 256)でした。  
動作の確認環境(開発環境)はwindows10, python3.9.5です。

mmapを選択した経緯としては、multiprocessingモジュールのSharedMemoryが、  
unixでは動作しないという情報がネットにあり、今回のプログラムをunix上でも動作させる可能性があるため、  
mmapを選択しました。

read_memory()の動作を単体で確認するため、  
共有メモリへ書き込みをするプログラム(c++)を作成し、同一PC内で動作させて正常に読み込みは確認できました。  
そのため、write_memory()の問題かと考えているのですが、  
mmapの使い方の作法の問題なのか、同一プロセス内で共有メモリのW->Rは不可なのか、原因がわからずにいます。  
どなたか教えて頂けないでしょうか。

実装コード

[code]

    import mmap
    import struct
    
    def read_memory():
      handle = mmap.mmap(0, 8, 'sample', mmap.ACCESS_READ)
      byte_data = handle.read()
      print('read byte:' + (str(byte_data)))
      shared_memory_info = struct.unpack('<II', byte_data)
      print('read data:' + (str(shared_memory_info)))
      handle.close()
    
    def write_memory():
      handle = mmap.mmap(0, 8, 'sample', mmap.ACCESS_WRITE)
      byte_data = struct.pack('<II', 128, 256)
      print('write byte:' + (str(byte_data)))
      handle.write(byte_data)
      handle.close()
    
    def main():
      write_memory()
      read_memory()
    
    if __name__ == '__main__':
      main()
    
[/code]

実行結果

[code]

    write byte:b'\x80\x00\x00\x00\x00\x01\x00\x00'
    read byte:b'\x00\x00\x00\x00\x00\x00\x00\x00'
    read data:(0, 0)
    
[/code]


CC BY-SA 4.0
2023-07-26T15:38:51.240
95770
2023-08-02T14:04:38.793
59268
question
python python3
windows環境下でmmapを使用した共有メモリに対してR/Wが動作しない


Linux で動作確認した修正例です。

  * 無名メモリにマップするために `mmap.mmap` には `fileno` として（0 では無く） -1 を渡す
  * `tagname` の指定は Unix でサポートされていないので、使用しない
  * 同じ `mmap` オブジェクトを使う（よって、少なくとも読む前には `seek` しておく必要が有る）

[code]

    import mmap
    import struct
    
    
    def read_memory(handle: mmap.mmap):
        handle.seek(0)
        byte_data = handle.read()
        print("read byte:" + (str(byte_data)))
        shared_memory_info = struct.unpack("<II", byte_data)
        print("read data:" + (str(shared_memory_info)))
    
    
    def write_memory(handle: mmap.mmap):
        handle.seek(0)
        byte_data = struct.pack("<II", 128, 256)
        print("write byte:" + (str(byte_data)))
        handle.write(byte_data)
    
    
    def main():
        # ファイルを使用する場合
        #with open("tmp.map", "r+") as mapfile, mmap.mmap(
        #    mapfile.fileno(), 8, access=mmap.ACCESS_WRITE
        #) as handle:
    
        with mmap.mmap(-1, 8, access=mmap.ACCESS_WRITE) as handle:
            write_memory(handle)
            read_memory(handle)
    
    
    if __name__ == "__main__":
        main()
    
[/code]


CC BY-SA 4.0
2023-07-26T22:43:00.123
95773
2023-07-26T23:24:44.960
2023-07-26T23:24:44.960
3054
3054
95770
answer


(別解に コメントでファイル割り当ても記されてるが,  
ファイルの扱い含めたコードとして)

mmapでファイルを割り当て, 毎回オープン・クローズする方法

  * ファイルが存在したら利用し, 無かったら作成
  * ファイルサイズが少し大きい程度ならそのままで構わないが, 足りない場合 `mm.resize()` などで合わせる必要がある

(Linuxで動作確認)

[code]

    import mmap
    import struct
    
    def read_memory(mm):
        # こういったアクセスも可能(念の為)。この場合 mm.seek(0) の指定は必要ない
        shared_memory_info = struct.unpack('<II', mm[0:8])
        print('read data:' + (str(shared_memory_info)))
    
    def write_memory(mm):
        fmt = '<II'
        mm[0:0 +struct.calcsize(fmt)] = struct.pack(fmt, 1234, 567)
    
    def main():
        from pathlib import Path
        fname = Path('file1.bin')
    
        if not fname.exists():
            with fname.open('wb') as fp:
                fp.truncate(8)
    
        with fname.open('r+b') as fp, mmap.mmap(fp.fileno(), 0) as mm:
            write_memory(mm)
        with fname.open('r+b') as fp, mmap.mmap(fp.fileno(), 0) as mm:
            read_memory(mm)
    
    if __name__ == '__main__':
        main()
    
[/code]


CC BY-SA 4.0
2023-08-02T14:04:38.793
95829
2023-08-02T14:04:38.793
43025
95770
answer