代码之家  ›  专栏  ›  技术社区  ›  mu5e

Rust,如何通过shm_open写入共享内存?

  •  0
  • mu5e  · 技术社区  · 5 年前

    我需要在C和Rust应用程序之间共享内存。 锈菌——生产者,消费者。

    在C语言中,我会创建一个共享内存区域,并将其传递给Rust进行编写。

    在C端,我使用如下内容:

    fd = shm_open(STORAGE_ID, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    res = ftruncate(fd, STORAGE_SIZE);
    addr = mmap(NULL, STORAGE_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
    // read from that memory after it is written by Rust app
    char data[STORAGE_SIZE];
    memcpy(data, addr, STORAGE_SIZE);
    

    在锈迹斑斑的一面,我该如何打开存储ID为的内存并对其进行写入? 我猜这是一个很好的例子,但却找不到可靠的例子:

    https://docs.rs/libc/0.2.77/libc/fn.shm_open.html

    https://docs.rs/memmap/0.6.1/memmap/struct.Mmap.html

    https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.clone_from_slice

    基本上,我需要做一些像这样的事情,但是要做好准备。c写在铁锈上: POSIX shared memory IPC example (shm_open, mmap), working on Linux and macOS

    0 回复  |  直到 5 年前
        1
  •  3
  •   Todd    5 年前

    用铁锈 libc 我们可以访问C进程可以访问的相同函数,所以Rust中的代码看起来与用C编写生成器时编写的代码非常相似。

    下面的代码演示了Rust code作为生产者和消费者。生产者和消费者以这种方式结合,只是为了有一个简单的例子,可以从命令行运行,以验证生产者代码的工作原理。

    在下面的代码中,位于 main() 函数与问题帖子中的代码相同。消费者和生产者都执行此操作以获得共享的内存区域。

    第一支 if 块将原始进程设置为使用者,使用者启动具有相同可执行文件的子进程。孩子的行刑路径将遵循 else 分支并写入内存的共享区域。

    父进程会一直阻塞,直到子进程完成,然后读取共享内存区域并打印它。

    use libc::{close, ftruncate, memcpy, mmap, shm_open, strncpy};
    use libc::{MAP_SHARED, O_RDWR, O_CREAT, PROT_WRITE, S_IRUSR, S_IWUSR};
    use libc::{c_char, c_void, off_t, size_t};
    use std::{env, ptr, str};
    use std::process::Command;
    use std::error::Error;
    
    const STORAGE_ID   : *const c_char = b"MY_MEM_ID\0".as_ptr() as *const c_char;
    const STORAGE_SIZE : size_t        = 128;
    
    
    fn main() -> Result<(), Box<dyn Error>>
    {
        let args = env::args().collect::<Vec<_>>();
        
        let (fd, addr) = unsafe {
            let null = ptr::null_mut();
            let fd   = shm_open(STORAGE_ID, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
            let _res = ftruncate(fd, STORAGE_SIZE as off_t);
            let addr = mmap(null, STORAGE_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
            
            (fd, addr)
        };
        if args.len() == 1 {
            // Consumer...
            
            let exec_path = &args[0];
            
            // Start producer process. Block until done.
            let output = Command::new(exec_path).arg("Producer...").output()?;
                                 
            println!("Producer stdout  : {}", str::from_utf8(&output.stdout)?);
            
            let mut data  = [0_u8; STORAGE_SIZE];
            let     pdata = data.as_mut_ptr() as *mut c_char;
            
            unsafe {
                strncpy(pdata, addr as *const c_char, STORAGE_SIZE);
                close(fd);
            }
            println!("Producer message : {}", str::from_utf8(&data)?);
            
        } else {
            // Producer...
    
            let data  = b"Hello, World!\0";
            let pdata = data.as_ptr() as *const c_void;
            
            unsafe {
                memcpy(addr, pdata, data.len());
            }
            print!("Done.");
        }
        Ok(())
    }
    

    输出:

    Producer stdout  : Done.
    Producer message : Hello, World!
    
    推荐文章