我有一个C程序和一个Rust程序,在它们之间,我成功地让它们讨论POSIX共享内存(C++和rust)。
我现在要做的是同步它们,我已经设法使用原子布尔创建了一个工作正常但效率低下的原始系统(在like this的基础上创建了AtomicBool
)。
然而,我真的希望使用互斥锁/condvar在线程之间进行同步,这就是我遇到的问题。
我似乎能够初始化它的C端,几乎逐字逐句地遵循这个例子。
我曾试图把它直接翻译成铁 rust :
let raw_shm = shm.get_shm();
let mut mtx_attrs = MaybeUninit::<nix::libc::pthread_mutexattr_t>::uninit();
if unsafe { nix::libc::pthread_mutexattr_init(mtx_attrs.as_mut_ptr()) } != 0 {
panic!("failed to create mtx_attrs");
};
let mtx_attrs = unsafe { mtx_attrs.assume_init() };
let mut cond_attrs = MaybeUninit::<nix::libc::pthread_condattr_t>::uninit();
if unsafe { nix::libc::pthread_condattr_init(cond_attrs.as_mut_ptr()) } != 0 {
panic!("failed to create cond_attrs");
};
let cond_attrs = unsafe { cond_attrs.assume_init() };
if unsafe {
nix::libc::pthread_mutexattr_setpshared(
&mtx_attrs as *const _ as *mut _,
PTHREAD_PROCESS_SHARED,
)
} != 0
{
panic!("failed to set mtx as process shared");
};
if unsafe {
nix::libc::pthread_condattr_setpshared(
&cond_attrs as *const _ as *mut _,
PTHREAD_PROCESS_SHARED,
)
} != 0
{
panic!("failed to set cond as process shared");
};
// I know that these offsets are correct, having used `offsetof` on the C++ side
let mtx_start = unsafe { &raw_shm.as_slice()[3110416] };
let mtx = unsafe { &*(mtx_start as *const _ as *const pthread_mutex_t) };
let cond_start = unsafe { &raw_shm.as_slice()[3110440] };
let cond = unsafe { &*(cond_start as *const _ as *const pthread_mutex_t) };
if unsafe {
nix::libc::pthread_mutex_init(&mtx as *const _ as *mut _, &mtx_attrs as *const _ as *mut _)
} != 0
{
panic!("failed to init mtx");
};
if unsafe {
nix::libc::pthread_cond_init(
&cond as *const _ as *mut _,
&cond_attrs as *const _ as *mut _,
)
} != 0
{
panic!("failed to init cond");
};
所有这些都通过了,返回值为0......到目前为止一切顺利。
我现在可以用两种方法之一测试它:
1.我可以设置这个简单的C++程序,让它停止在condvar中等待:
if (pthread_mutex_lock(&shmp->mutex) != 0)
throw("Error locking mutex");
if (pthread_cond_wait(&shmp->condition, &shmp->mutex) != 0)
throw("Error waiting for condition variable");
在铁 rust 中:
let sig = unsafe { nix::libc::pthread_cond_signal(&cond as *const _ as *mut _) };
dbg!(sig);
尽管返回了0
(即成功),但我的C程序没有发布超过condvar;它保持等待,就好像它从未接收到信号一样。
1.我可以设置另一个平凡的C程序,它在循环中不断地向条件变量发送信号:
for (unsigned int count = 0;; count++) {
if (pthread_cond_signal(condition) != 0)
throw("Error")
// sleep for a bit
}
然后在铁 rust 里,就像这样:
loop {
if unsafe { nix::libc::pthread_mutex_lock(&mtx as *const _ as *mut _) } > 0 {
panic!("Failed to acquire lock")
};
if unsafe {
nix::libc::pthread_cond_wait(&cond as *const _ as *mut _, &mtx as *const _ as *mut _)
} > 0
{
panic!("Failed to acquire lock")
};
}
这样做,锁定互斥锁的调用是成功的,但是我得到了一个EINVAL
对pthread_cond_wait
定义的here,我似乎无法纠正...
我觉得我快成功了......有什么想法可以让它成功吗?(这主要是一个概念验证)。
1条答案
按热度按时间toe950271#
为了子孙后代,我已经设法让这个工作。
为了阐明程序的架构,有两个二进制文件:一个C和一个Rust。Rust程序使用
std::process::Command
生成C程序。为简洁起见,省略了错误处理和导入。
共享内存块的结构如下:
共享内存块初始化为零,因此
ready
将始终以false
开始。std::process::Command::spawn
生成c++程序,然后在循环中等待,直到ready
变为true
。mmap
到本地地址空间。mutex
和condition
,然后将内存块标记为就绪。然后在以下条件下进入循环信令:
1.现在,rust程序已经从步骤2)中的循环中释放出来了,具体化在步骤4)中初始化的互斥锁和条件。
现在我们可以等待条件,得到c++程序的通知。