微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决如何通过 shm_open 写入共享内存?

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

在 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);

在 Rust 端我该怎么做才能打开带有 STORAGE_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

基本上,我需要做这样的事情,但是 set.c 是用 Rust 编写的: POSIX shared memory IPC example (shm_open,mmap),working on Linux and macOS

解决方法

使用 Rust 的 libc crate,我们可以访问 C 进程可以访问的相同函数,因此 Rust 中的代码看起来与您在 C 中编写生产者时编写的代码非常相似。

下面的代码将 Rust 代码演示为生产者和消费者。以这种方式组合生产者和消费者只是为了有一个可以从命令行运行的简单示例,以验证 Rust 生产者代码是否有效。

在下面的代码中,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,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!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。