Multithreading 如何使用共享内存修改一个线程中的值并读取另一个线程中的值?
下面的Python代码创建了一个线程(实际上是一个进程),其中一个数组包含传递给它的两个浮点数,线程每5秒对第一个浮点数计数1,对第二个浮点数计数-1,而主线程则连续打印这两个浮点数:Multithreading 如何使用共享内存修改一个线程中的值并读取另一个线程中的值?,multithreading,rust,shared-memory,Multithreading,Rust,Shared Memory,下面的Python代码创建了一个线程(实际上是一个进程),其中一个数组包含传递给它的两个浮点数,线程每5秒对第一个浮点数计数1,对第二个浮点数计数-1,而主线程则连续打印这两个浮点数: from multiprocessing import Process, Array from time import sleep def target(states): while True: states[0] -= 1 states[1] += 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中使用共享内存做同样的事情?我试着做了以下几点():
但这会产生一个编译错误:
错误:无法索引'std::sync::Arc类型的值`
-->,但我仍然不知道如何执行此操作。好的,让我们首先修复编译器错误:
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\u 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]);
}
这将始终产生正确的结果。您的代码并不遥远!:)
让我们先看看编译器错误:它表明您显然正在尝试索引某些内容。这是正确的,您希望为数据
变量编制索引(使用数据[0]
),但编译器抱怨您要编制索引的值的类型为std::sync::Arc
,无法编制索引
如果您查看该类型,您很快就会看到:我的数组仍然包装在一个互斥体中
,它包装在一个弧中
。这就带来了解决方案:您也必须锁定读取访问。因此,您必须添加lock().unwrap()
,就像在另一个线程中一样:
print!("{}", data.lock().unwrap()[0]);
但现在出现了一个新的编译器错误:使用移动值:`data`
。该死!这来自你的名字阴影。你说let data=data.clone()代码>在启动线程之前;这会对原始的数据进行阴影处理。那么我们用let data\u for_thread=data.clone()
替换它,并在另一个线程中使用data\u for_thread
?你可以看到工作结果
让它做与Python示例相同的事情不再那么困难了,是吗
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]);
}
您可以尝试一下,尽管我做了一些小改动,允许在操场上跑步。如果通过线程更新公共数据,其他线程可能看不到更新的值,除非您执行以下操作:
将变量声明为volatile,以确保将最新更新返回给读取该变量的线程。数据是从内存块读取的,而不是从缓存读取的
使所有更新和读取同步化,这可能会导致性能方面的代价高昂,但一定要解决由于不同线程的写入和读取的非同步方法而导致的数据损坏/一致性问题
另外,您可以这样修复编译错误:(我在那里为演示添加了一个sleep()):如果您不再使用三个不同的、相互隐藏的变量(称为data
)来混淆自己,您可能会自己找到解决方案。在Rust中,一个变量不会声明为volatile。也没有“synchronized”关键字,如果这是您的意思的话。您可以通过为执行读写操作的线程在对象上创建隐式锁来做到这一点。无法相信python不提供监视器锁定功能。请查看以下链接了解详细信息。您可能希望重新阅读问题,以仔细检查您试图给出答案的语言。无论您使用何种语言编程,每种语言都具有锁定功能。多线程是所有语言的通用实现。无论如何,我在回答时考虑的是Java。请不要假设所有语言都以相同的方式进行并发编程。在这里,没有人会期待一个不了解Rust中并发编程的人给出答案。
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]);
}