Concurrency 是否可能只允许一个线程改变共享数据?

Concurrency 是否可能只允许一个线程改变共享数据?,concurrency,rust,Concurrency,Rust,是否有任何方法可以在线程之间共享数据(使用Arc),但只允许单个线程能够修改该数据 类似的东西在C中是可能的,但我不知道如何在Rust中做到这一点 Arc允许所有线程变异,而Arc不允许任何线程变异。您可以在Arc周围创建一个包装器,并使用Arc创建者提供的键通过setter方法设置值 use std::sync::Arc; use std::sync::Mutex; use std::thread; #[derive(Clone)] pub struct CustomArc<T>

是否有任何方法可以在线程之间共享数据(使用
Arc
),但只允许单个线程能够修改该数据

类似的东西在C中是可能的,但我不知道如何在Rust中做到这一点


Arc
允许所有线程变异,而
Arc
不允许任何线程变异。

您可以在
Arc
周围创建一个包装器,并使用Arc创建者提供的键通过setter方法设置值

use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

#[derive(Clone)]
pub struct CustomArc<T> {
    mutable_arc: Arc<Mutex<T>>,
    mutator_key: String,
}

#[derive(Clone)]
struct MyStruct {
    inner_val: i32,
}

impl MyStruct {
    fn set_val(&mut self, val: i32) {
        self.inner_val = val;
    }

    fn get_val(&mut self) -> i32 {
        self.inner_val.clone()
    }
}

impl CustomArc<MyStruct> {
    fn new(val: MyStruct, mutator_key: String) -> CustomArc<MyStruct> {
        CustomArc {
            mutable_arc: Arc::new(Mutex::new(val)),
            mutator_key,
        }
    }

    fn set_inner_val(&mut self, value: i32, mutator_key: String) -> Result<(), SetError> {
        if mutator_key == self.mutator_key {
            self.mutable_arc.lock().unwrap().set_val(value);
            return Ok(());
        }

        Err(SetError::CouldNotSet)
    }

    fn get_inner_val(&self) -> i32 {
        self.mutable_arc.lock().unwrap().get_val()
    }
}

enum SetError {
    CouldNotSet,
}

fn main() {
    let my_struct = MyStruct { inner_val: 3 };

    let custom_arc = CustomArc::new(my_struct, "OwnerKey".to_string());
    let mut custom_arc1 = custom_arc.clone();
    let mut custom_arc2 = custom_arc.clone();
    let mut custom_arc3 = custom_arc.clone();

    thread::spawn(move || {
        println!(
            "Thread1 -> Current Value: {:?}",
            custom_arc1.get_inner_val()
        );
        if let Err(_err) = custom_arc1.set_inner_val(4, "AnotherKey".to_string()) {
            println!("Could not write in thread1");
        }
        println!("Thread1 -> Value: {:?}", custom_arc1.get_inner_val());
    });

    thread::sleep_ms(500);

    thread::spawn(move || {
        println!(
            "Thread2 -> Current Value: {:?}",
            custom_arc2.get_inner_val()
        );
        if let Err(_err) = custom_arc2.set_inner_val(5, "OwnerKey".to_string()) {
            println!("Could not write in thread2");
        }
        println!("Thread2 -> Value: {:?}", custom_arc2.get_inner_val());
    });

    thread::sleep_ms(500);

    thread::spawn(move || {
        println!(
            "Thread3 -> Current Value: {:?}",
            custom_arc3.get_inner_val()
        );
        if let Err(_err) = custom_arc3.set_inner_val(6, "SomeKey".to_string()) {
            println!("Could not write in thread3");
        }
        println!("Thread3 -> Value: {:?}", custom_arc3.get_inner_val());
    });

    thread::sleep_ms(500);
}
使用std::sync::Arc;
使用std::sync::Mutex;
使用std::线程;
#[衍生(克隆)]
pub结构CustomArc{
可变弧:弧,
mutator_键:字符串,
}
#[衍生(克隆)]
结构MyStruct{
内华达州:i32,
}
impl MyStruct{
fn set_val(&mut self,val:i32){
self.inner_val=val;
}
fn获取值(&mut self)->i32{
self.internal_val.clone()
}
}
impl自定义弧{
fn新(val:MyStruct,mutator_key:String)->CustomArc{
海关总署{
可变_弧:弧::新(互斥体::新(val)),
突变键,
}
}
fn set_internal_val(&mut self,value:i32,mutator_key:String)->Result{
如果mutator\u key==self.mutator\u key{
self.mutable_arc.lock().unwrap().set_val(值);
返回Ok(());
}
Err(SetError::CouldNotSet)
}
fn获取内部值(&self)->i32{
self.mutable_arc.lock().unwrap().get_val()
}
}
枚举设置错误{
无法设置,
}
fn main(){
让my_struct=MyStruct{inner_val:3};
让custom_arc=CustomArc::new(我的结构,“OwnerKey.”到_string();
让mut custom_arc1=custom_arc.clone();
让mut custom_arc2=custom_arc.clone();
让mut custom_arc3=custom_arc.clone();
线程::生成(移动| |{
普林顿(
“Thread1->当前值:{:?}”,
自定义_arc1.get_inner_val()
);
如果let Err(_Err)=custom_arc1.设置_internal_val(4,“另一个键”。设置为_string()){
println!(“无法在thread1中写入”);
}
println!(“Thread1->Value:{:?}”,自定义_arc1.get_inner_val());
});
线程:sleep_ms(500);
线程::生成(移动| |{
普林顿(
“Thread2->当前值:{:?}”,
自定义_arc2.get_inner_val()
);
如果let Err(_Err)=custom_arc2.将_internal_val(5,“OwnerKey.”设置为_string(){
println!(“无法在thread2中写入”);
}
println!(“Thread2->Value:{:?}”,自定义_arc2.get_inner_val());
});
线程:sleep_ms(500);
线程::生成(移动| |{
普林顿(
“Thread3->当前值:{:?}”,
自定义_arc3.get_inner_val()
);
如果let Err(_Err)=自定义_arc3.将_internal_val(6,“SomeKey.”设置为_string(){
println!(“无法在thread3中写入”);
}
println!(“Thread3->Value:{:?}”,自定义_arc3.get_inner_val());
});
线程:sleep_ms(500);
}


由于您的
CustomArc
是公共的,而
mutable_arc
字段是私有的,因此您应该从机箱外部通过setter和getter访问它们。
mutator\u键的所有者(可能是另一个线程)有权对内部数据进行变异。

您可以使用类型系统包装
,除非由一个特权所有者进行变异,否则不允许变异。下面是一个例子:

use std::sync::Arc;
use std::sync::Mutex;

pub struct Writer<T>(Arc<Mutex<T>>);

impl<T> Writer<T> {
    pub fn new(value: T) -> Self {
        Writer(Arc::new(Mutex::new(value)))
    }

    pub fn reader(&self) -> Reader<T> {
        Reader(Arc::clone(&self.0))
    }

    pub fn set(&self, value: T) {
        *self.0.lock().unwrap() = value;
    }

    pub fn get(&self) -> T
    where
        T: Clone,
    {
        self.0.lock().unwrap().clone()
    }
}

pub struct Reader<T>(Arc<Mutex<T>>);

// derive(Clone) uses incorrect bounds, so we must implement Clone manually
// (see https://stackoverflow.com/q/39415052/3650362)
impl<T> Clone for Reader<T> {
    fn clone(&self) -> Self {
        Reader(Arc::clone(&self.0))
    }
}

impl<T> Reader<T> {
    pub fn get(&self) -> T
    where
        T: Clone,
    {
        self.0.lock().unwrap().clone()
    }
}
使用std::sync::Arc;
使用std::sync::Mutex;
发布结构编写器(Arc);
impl编写器{
发布fn新(值:T)->Self{
Writer(Arc::new(Mutex::new(value)))
}
发布fn阅读器(&self)->阅读器{
读卡器(Arc::clone(&self.0))
}
发布fn集(&self,值:T){
*self.0.lock().unwrap()=值;
}
发布fn获取(&self)->T
哪里
T:克隆,
{
self.0.lock().unwrap().clone()
}
}
发布结构阅读器(Arc);
//派生(克隆)使用了不正确的边界,因此我们必须手动实现克隆
//(见https://stackoverflow.com/q/39415052/3650362)
读卡器的impl克隆{
fn克隆(&self)->self{
读卡器(Arc::clone(&self.0))
}
}
impl阅读器{
发布fn获取(&self)->T
哪里
T:克隆,
{
self.0.lock().unwrap().clone()
}
}
如果您将此代码放入
模块
中,Rust的隐私控制将证明,除非使用
不安全
,否则任何用户都无法复制
编写器
,或将
读卡器
变成
编写器
。因此,您可以克隆
读卡器
并将其发送到任意多个线程,但只能将
写卡器
发送到应该具有写访问权限的特定线程

这种设计有许多可能的变化;例如,您可以使用
RwLock
而不是
Mutex
来让多个读卡器在不写入值时同时访问该值

(基于Akiner Alkan的例子)

这样的事情在C语言中是可能的


请注意,正如在Rust中一样,如果希望在C中安全地执行此操作,则需要某种类型的同步(互斥或类似)。Rust坚持要明确如何避免数据竞争。C的不同之处在于,它只会假设你知道自己在做什么,然后因为你写比赛而严厉惩罚你。在Rust中,惯用的方法是使用标准库提供的安全抽象。但是,如果您有其他一些同步方法,并且可以证明
互斥
是不必要的开销,那么您总是可以用C的方式编写东西——原始指针在Rust(在
不安全的
块中)和C中本质上是相同的。

您在寻找现成的东西吗?似乎您可以在
Arc
周围创建一个只公开读取操作的包装器类型,然后只将该包装器发送给读取线程,这样它们就永远无法直接访问
Arc
,因此无法获得写访问权。在C中可以做的任何事情,您都可以用同样的方式来做--