首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为结构创建*mut *mut

为结构创建*mut *mut
EN

Stack Overflow用户
提问于 2017-02-14 20:52:34
回答 2查看 3.6K关注 0票数 7

我试图用指向我的结构的指针调用pthread_join,以便C线程能够将结构填充到我指向的内存。(是的,我知道这是非常不安全的。)

pthread_join的函数签名

代码语言:javascript
复制
pub unsafe extern fn pthread_join(native: pthread_t,
                                  value: *mut *mut c_void)
                                  -> c_int

我这样做是为了练习将C代码从一本书移植到Rust。C代码:

代码语言:javascript
复制
pthread_t   tid1;
struct foo  *fp;
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
err = pthread_join(tid1, (void *)&fp);

我想出了一个密码:

代码语言:javascript
复制
extern crate libc;
use libc::{pthread_t, pthread_join};

struct Foo {}

fn main() {
    let tid1:pthread_t = std::mem::uninitialized();
    let mut fp:Box<Foo> = std::mem::uninitialized();
    let value = &mut fp;
    pthread_join(tid1, &mut value);
}

但我看到的错误是:

代码语言:javascript
复制
error[E0308]: mismatched types
  --> src/bin/11-threads/f04-bogus-pthread-exit.rs:51:24
   |
51 |     pthread_join(tid1, &mut value);
   |                        ^^^^^^^^^^ expected *-ptr, found mutable reference
   |
   = note: expected type `*mut *mut libc::c_void`
              found type `&mut &mut std::boxed::Box<Foo>`

仅仅使用强制转换就可以实现这一点,还是我需要转换?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-15 11:31:40

这里有几个问题:

  • Box是一个指向堆分配资源的指针,您可以使用Box::into_raw(some_box)提取指针本身,
  • 引用并不会被静默地强制到指针中(即使它们具有相同的表示形式),您需要显式的转换,
  • 您需要将您的具体类型转换为c_void,类型推断可能会做到这一点。
  • 您有对指针的引用,需要指向指针的指针;您有太多的间接级别。

让我们把它做好:

代码语言:javascript
复制
// pthread interface, reduced
struct Void;

fn sample(_: *mut *mut Void) {}

// actual code
struct Foo {}

fn main() {
    let mut p = Box::into_raw(Box::new(Foo{})) as *mut Void;
    sample(&mut p as *mut _);
}

请注意,这是内存泄漏(由于into_raw的结果),通常应该将内存塞回带有from_rawBox中,以便调用Foo的析构函数并释放内存。

票数 6
EN

Stack Overflow用户

发布于 2017-02-14 21:38:56

代码不能按编写的方式工作;这是因为C线程实际上没有在所指向的内存中“填充结构”。它负责分配自己的内存(或预先从另一个线程接收内存)并填写。C线程“返回”的唯一东西是一个地址,这个地址由pthread_join获取。

这就是为什么pthread_join接收一个void **,即指向void *的指针。这种输出参数使pthread_join能够存储(返回)刚完成的线程提供的void *指针。线程可以通过将指针传递给pthread_exit或从传递给pthread_createstart_routine返回指针来提供指针。在Rust中,可以使用如下代码接收原始指针:

代码语言:javascript
复制
let mut c_result: *mut libc::c_void = ptr::null_mut();
libc::pthread_join(tid1, &mut c_result as *mut _);
// C_RESULT now contains the raw pointer returned by the worker's
// start routine, or passed to pthread_exit()

返回指针所指向的内存的内容和大小是要连接的线程与连接它的线程之间的契约问题。如果工作线程是用C实现的,并且设计为被其他C代码调用,那么一个明显的选择就是为结果结构分配内存,填充它,并提供一个指向分配内存的指针。例如:

代码语言:javascript
复制
struct ThreadResult { ... };

...
ThreadResult *result = malloc(sizeof(struct ThreadResult));
result->field1 = value1;
...
pthread_exit(result);

在这种情况下,加入线程的Rust代码可以通过复制C结构并获取其所有权来解释结果:

代码语言:javascript
复制
// obtain a raw-pointer c_result through pthread_join as 
// shown above:
let mut c_result = ...;
libc::pthread_join(tid1, &mut c_result as *mut _);

#[repr(C)]
struct ThreadResult { ... } // fields copy-pasted from C

unsafe {
    // convert the raw pointer to a Rust reference, so that we may
    // inspect its contents
    let result = &mut *(c_result as *mut ThreadResult);

    // ... inspect result.field1, etc ...

    // free the memory allocated in the thread
    libc::free(c_result);
    // RESULT is no longer usable
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42235980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档