包含原始指针的结构可以实现发送并且FFI安全吗? [英] Can a struct containing a raw pointer implement Send and be FFI safe?

查看:69
本文介绍了包含原始指针的结构可以实现发送并且FFI安全吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个场景,Rust将调用C到malloc缓冲区并将结果指针存储到结构中.稍后,该结构将被移至线程并传递给C函数以对其进行变异.

I have a scenario where Rust will call C to malloc a buffer and stash the resulting pointer into a struct. Later on, the struct will be moved to a thread and passed to a C function which mutates it.

天真的解决方法看起来像这样(游乐场):

The naive approach to my problem looks like this (playground):

extern crate libc;

use libc::{c_void, malloc, size_t};
use std::thread;

const INITIAL_CAPACITY: size_t = 8;

extern "C" {
    fn mutate(s: *mut Storage);
}

#[repr(C)]
struct Storage {
    #[allow(dead_code)]
    buf: *mut c_void,
    capacity: usize,
}

fn main() {
    let buf = unsafe { malloc(INITIAL_CAPACITY) };
    let mut s = Storage {
        buf: buf,
        capacity: INITIAL_CAPACITY,
    };
    thread::spawn(move || {
        unsafe {
            mutate(&mut s); // mutates s.val, maybe reallocates it, updating s.capacity if so.
        }
    }).join()
        .unwrap();
}

赠予:

error[E0277]: the trait bound `*mut libc::c_void: std::marker::Send` is not satisfied in `[closure@src/main.rs:26:19: 30:6 s:Storage]`
  --> src/main.rs:26:5
   |
26 |     thread::spawn(move || {
   |     ^^^^^^^^^^^^^ `*mut libc::c_void` cannot be sent between threads safely
   |
   = help: within `[closure@src/main.rs:26:19: 30:6 s:Storage]`, the trait `std::marker::Send` is not implemented for `*mut libc::c_void`
   = note: required because it appears within the type `Storage`
   = note: required because it appears within the type `[closure@src/main.rs:26:19: 30:6 s:Storage]`
   = note: required by `std::thread::spawn`

这是编译器的一种说法,因为*mut c_void没有实现SendStorage也没有实现,所以您不能将其移入线程闭包.

Which is the compiler's way of saying that because a *mut c_void doesn't implement Send, neither does Storage so you can't move it into the thread closure.

我认为使用Unique指针可能会解决此问题.让我们尝试一下(游乐场):

I thought that using a Unique pointer might solve this. Let's try it (playground):

#![feature(ptr_internals)]
extern crate libc;

use libc::{c_void, malloc, size_t};
use std::ptr::Unique;
use std::thread;

const INITIAL_CAPACITY: size_t = 8;

extern "C" {
    fn mutate(s: *mut Storage);
}

#[repr(C)]
struct Storage {
    #[allow(dead_code)]
    buf: Unique<c_void>,
    capacity: usize,
}

fn main() {
    let buf = Unique::new(unsafe { malloc(INITIAL_CAPACITY) }).unwrap();
    let mut s = Storage {
        buf: buf,
        capacity: INITIAL_CAPACITY,
    };
    thread::spawn(move || {
        unsafe {
            mutate(&mut s); // mutates s.val, maybe reallocates it, updating s.capacity if so.
        }
    }).join()
        .unwrap();
}

但这给出了:

warning: `extern` block uses type `std::ptr::Unique<libc::c_void>` which is not FFI-safe: this struct has unspecified layout
  --> src/main.rs:11:18
   |
11 |     fn mutate(s: *mut Storage);
   |                  ^^^^^^^^^^^^
   |
   = note: #[warn(improper_ctypes)] on by default
   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct

是否有一种方法可以使Storage结构既实现Send又具有指向其实例的可变指针是FFI安全的?

Is there a way to have the Storage struct both implement Send and have mutable pointers to its instances be FFI safe?

推荐答案

默认情况下,Rust假定*mut T在线程之间发送不安全,这意味着包含它的结构也不安全.

By default Rust assumes *mut T is not safe to send between threads, and this means structs containing it are not safe either.

您可以告诉Rust确实是安全的:

You can tell Rust that it is safe indeed:

unsafe impl Send for Storage {}

它完全取决于您对C如何使用此指针后面的数据的了解.实现Send意味着,在使用此指针后面的对象时,C将不依赖于线程本地存储或特定于线程的锁(反常地,对于大多数线程不安全"的C代码而言,这都是正确的).

It relies entirely on your knowledge of how C uses data behind this pointer. Implementing Send means C won't rely on thread-local storage or thread-specific locks when using the object behind this pointer (paradoxically, that's true for most "thread-unsafe" C code).

不需要c一次处理来自多个线程的访问-这就是Sync的目的.

It doesn't require C to handle access from multiple threads at once — that's what Sync is for.

这篇关于包含原始指针的结构可以实现发送并且FFI安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆