Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Rust RwLock在使用叉子时会出现意外行为?_Rust_Multiprocessing_Locking_Fork_Mutex - Fatal编程技术网

为什么Rust RwLock在使用叉子时会出现意外行为?

为什么Rust RwLock在使用叉子时会出现意外行为?,rust,multiprocessing,locking,fork,mutex,Rust,Multiprocessing,Locking,Fork,Mutex,我看到了一些我无法解释的行为,当我使用锁和叉的时候。基本上,子进程报告一个仍被获取的RwLock,而父进程则没有,即使它们都运行相同的代码路径。我的理解是,子进程应该接收父进程内存空间(包括锁)的独立副本,因此它们应该报告不同的结果是没有意义的 预期的行为是子级和父级都报告“mutex hold:false”。有趣的是,当使用互斥锁而不是RwLock时,这就像预期的那样工作 我猜你是在Linux系统上运行的。Rust之所以这样做是因为glibc做到了这一点,Rust的rBlock基于glibc

我看到了一些我无法解释的行为,当我使用锁和叉的时候。基本上,子进程报告一个仍被获取的RwLock,而父进程则没有,即使它们都运行相同的代码路径。我的理解是,子进程应该接收父进程内存空间(包括锁)的独立副本,因此它们应该报告不同的结果是没有意义的

预期的行为是子级和父级都报告“mutex hold:false”。有趣的是,当使用互斥锁而不是RwLock时,这就像预期的那样工作


我猜你是在Linux系统上运行的。Rust之所以这样做是因为glibc做到了这一点,Rust的
rBlock
基于glibc在使用Linux系统的glibc上的pthreads实现

您可以使用等效的C程序确认此行为:

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;

    pthread_rwlock_wrlock(&lock);
    pid_t pid = fork();
    int res = pthread_rwlock_unlock(&lock);
    int res2 = pthread_rwlock_trywrlock(&lock);

    printf("%s unlock_errno=%d trywrlock_errno=%d\n", (pid == 0) ? "child" : "parent", res, res2);
    return 0;
}
16在我的系统上是EBUSY

glibc发生这种情况的原因是POSIX为rwlocks指定了一个解锁函数,glibc存储当前线程ID以确定当前线程持有的锁是读锁还是写锁。如果当前线程ID等于存储的值,则该线程具有写锁,否则具有读锁。因此,您实际上没有解锁子系统中的任何内容,但很可能损坏了锁中的读卡器计数器


正如注释中提到的,根据POSIX,这是子线程中未定义的行为,因为线程解锁不是持有锁的线程。为了实现这一点,Rust必须像Go一样实现自己的同步原语,这通常是一个主要的可移植性噩梦。

工作原理是,这只是未定义的行为:“如果读写锁rBlock不由调用线程持有,则结果未定义。”看起来,即使分叉进程有父级内存的副本,锁的状态中也必须有线程id,从而导致其行为异常。^这似乎是我的答案,再加上这些同步抽象通常构建在操作系统原语()之上的事实,因此可能会泄露实施细节,尤其是在
不安全的情况下。
PARENT mutex held: false
CHILD mutex held: true
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;

    pthread_rwlock_wrlock(&lock);
    pid_t pid = fork();
    int res = pthread_rwlock_unlock(&lock);
    int res2 = pthread_rwlock_trywrlock(&lock);

    printf("%s unlock_errno=%d trywrlock_errno=%d\n", (pid == 0) ? "child" : "parent", res, res2);
    return 0;
}
parent unlock_errno=0 trywrlock_errno=0
child unlock_errno=0 trywrlock_errno=16