如何修改一个线程中的值并使用共享内存读取另一个线程中的值?

时间:2016-09-10 09:32:07

标签: multithreading rust shared-memory

以下Python代码创建一个线程(实际上是一个进程),其中一个数组包含两个传递给它的浮点数,该线程由第一个浮点数计数1,第二个浮点数每隔5秒计数-1,而主线程为连续打印两个花车:

from multiprocessing import Process, Array
from time import sleep

def target(states):
    while True:
        states[0] -= 1
        states[1] += 1
        sleep(5)

def main():
    states = Array("d", [0.0, 0.0])
    process = Process(target=target, args=(states,))
    process.start()
    while True:
        print(states[0])
        print(states[1])

if __name__ == "__main__":
    main()

如何在Rust中使用共享内存做同样的事情?我尝试过以下操作(playground):

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new([0.0]));
    let data = data.clone();
    thread::spawn(move || {
        let mut data = data.lock().unwrap();
        data[0] = 1.0;
    });
    print!("{}", data[0]);
}

但是这给出了编译错误:

error: cannot index a value of type `std::sync::Arc<std::sync::Mutex<[_; 1]>>`
  --> <anon>:12:18
   |>
12 |>     print!("{}", data[0]);
   |>                  ^^^^^^^

即使它起作用,它也会有所不同。我已经阅读了this,但我仍然不知道该怎么做。

3 个答案:

答案 0 :(得分:3)

你的代码并不遥远! :)

让我们先看一下编译器错误:它说你显然是在尝试索引某些内容。这是事实,您希望索引data变量(带data[0]),但编译器会抱怨您要索引的值是std::sync::Arc<std::sync::Mutex<[_; 1]>>类型且无法编入索引。

如果查看类型,可以快速查看:我的数组仍然包含在Mutex<T>中,Arc<T>包含在lock().unwrap()中。这给我们带来了解决方案:你必须锁定读取权限。所以你必须在另一个帖子中添加print!("{}", data.lock().unwrap()[0]); 之类:

use of moved value: `data`

但是现在出现了一个新的编译器错误:let data = data.clone();。党!这来自你的名字阴影。你在开始线程之前说data;这会影响原始let data_for_thread = data.clone()。那么我们如何用data_for_thread替换它并在另一个线程中使用use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; let data = Arc::new(Mutex::new([0.0, 0.0])); let data_for_thread = data.clone(); thread::spawn(move || { loop { thread::sleep(Duration::from_secs(5)) let mut data = data_for_thread.lock().unwrap(); data[0] += 1.0; data[1] -= 1.0; } }); loop { let data = data.lock().unwrap(); println!("{}, {}", data[0], data[1]); } 呢?您可以看到工作结果here on the playground

让它与Python示例做同样的事情不再那么难了,是吗?

#[xpath3('total',payload,'NUMBER') is java.lang.Number ? xpath3('total',payload,'NUMBER') : 0]

你可以尝试here on the playground,虽然我改变了一些小事以允许在操场上跑步。

答案 1 :(得分:1)

好的,让我们先解决编译错误:

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new([0.0]));
    let thread_data = data.clone();
    thread::spawn(move || {
        let mut data = thread_data.lock().unwrap();
        data[0] = 1.0;
    });
    println!("{}", data.lock().unwrap()[0]);
}

变量thread_data总是被移入线程,这就是在生成线程后无法访问它的原因。 但是这仍然有一个问题:你正在启动一个与主线程同时运行的线程,最后一个print语句将在线程在大多数时间改变值之前执行(它将是随机的)。

要解决此问题,您必须等待线程完成才能打印值:

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new([0.0]));
    let thread_data = data.clone();
    let t = thread::spawn(move || {
        let mut data = thread_data.lock().unwrap();
        data[0] = 1.0;
    });
    t.join().unwrap();
    println!("{}", data.lock().unwrap()[0]);
}

这将始终产生正确的结果。

答案 2 :(得分:-3)

If you update common data by a thread, the other threads might not see the updated value, unless you do the following:

  1. Declare the variable as volatile which makes sure that the latest update is given back to the threads that read the variable. The data is read from the memory block but not from cache.

  2. Make all updates and reads as synchronized which might turn out to be costly in terms of performance but is sure to deal with data corruptions/in-consistency due to non-synchronization methods of writes and reads by distinct threads.