当前位置: 首页 > 知识库问答 >
问题:

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

孟树
2023-03-14

我需要在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是用Rust编写的:POSIX共享内存IPC示例(shm_open,mmap),在Linux和macOS上工作

共有1个答案

濮金鑫
2023-03-14

使用Rust的libccrate,我们可以访问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!
 类似资料:
  • 问题内容: 我想知道这个著名报价的最真实的解释是什么: 不要通过共享内存进行交流;通过通信共享内存。(R.派克) 在Go Memory Model中,我可以阅读以下内容: 通道上的发送发生在该通道上的相应接收完成之前。(Golang规格) 还有一篇专门的golang文章解释了报价。而关键的贡献是一个工作例子也由Andrew G. 好。有时谈论太多....我是从“内存规范”引用中得出的,也可以通过查

  • 问题内容: 我的机器在端口8080上运行着jboss,我想在网络上共享jboss服务器,以便我使用jbossws- native-4.0.2运行jboss服务,但是我仍然无法访问网络上的jboss服务器,请帮助。 问题答案: 启动jboss(run.sh或run.bat)时使用选项-b 0.0.0.0,这会将端口绑定到所有网络接口。默认值为localhost,这就是为什么您无法通过网络访问服务器的

  • 通过查看shmget()的手动页面,我了解到shmget()调用在内存中分配了#个页面,这些页面可以在进程之间共享。 它是否要创建内核内存页,并将其映射到进程的本地地址空间?还是为该段保留了相同的进程内存页,并将为其他附加进程共享相同的内存页? 调用shmget()时,内核将保留一定数量的段/页。 调用shmat()时,保留的段映射到进程的地址空间/页。 当一个新进程附加到同一段时,前面创建的内核

  • 问题内容: 这是我的代码,但这是针对单个文件的解决方案。 我可以像下面的单个文件一样共享多个文件和上载吗? 问题答案: 是的,但是您需要使用而不是。 这绝对可以简化,但我在其中保留了一些内容,以便您可以分解所需的每个步骤。 更新 :从API 24开始,共享文件URI将导致FileUriExposedException。为了解决这个问题,您可以将compileSdkVersion切换为23或更低版本

  • 我正在开发一个应用程序,它必须通过whatsapp共享mp3文件。 我现在的代码如下: 例如,我可以通过Gmail成功共享,但通过whatsapp无法实现。这是我的代码的问题还是whatsapp不允许你共享mp3文件? 提前感谢!

  • 我试图通过在我的iOS应用程序上添加共享文本+URL的功能,但一直失败。 > 发生的情况是Messenger正在打开,但没有内容(文本和url都丢失)。 也许有人知道吗?我的应用程序还在沙箱里,也许这就是原因? 这是我使用的代码: