Multithreading 如何使用mpsc通道在线程之间创建环形通信?
我希望生成n个线程,使其能够与环形拓扑中的其他线程通信,例如,线程0可以向线程1发送消息,线程1向线程2发送消息,等等,线程n向线程0发送消息 这是我想用n=3实现的一个示例:Multithreading 如何使用mpsc通道在线程之间创建环形通信?,multithreading,rust,channel,Multithreading,Rust,Channel,我希望生成n个线程,使其能够与环形拓扑中的其他线程通信,例如,线程0可以向线程1发送消息,线程1向线程2发送消息,等等,线程n向线程0发送消息 这是我想用n=3实现的一个示例: 使用std::sync::mpsc:{self,Receiver,Sender}; 使用std::线程; let(tx0,rx0):(发送方,接收方)=mpsc::channel(); let(tx1,rx1):(发送方,接收方)=mpsc::channel(); let(tx2,rx2):(发送方,接收方)=mpsc:
使用std::sync::mpsc:{self,Receiver,Sender};
使用std::线程;
let(tx0,rx0):(发送方,接收方)=mpsc::channel();
let(tx1,rx1):(发送方,接收方)=mpsc::channel();
let(tx2,rx2):(发送方,接收方)=mpsc::channel();
让child0=thread::spawn(移动| |){
tx0.send(0.unwrap();
println!(“线程0已发送:0”);
println!(“线程0 recv:{:?}”,rx2.recv().unwrap());
});
让child1=thread::spawn(移动| |){
tx1.send(1.unwrap();
println!(“线程1已发送:1”);
println!(“线程1 recv:{:?}”,rx0.recv().unwrap());
});
让child2=thread::spawn(移动| |){
tx2.send(2.unwrap();
println!(“线程2已发送:2”);
println!(“线程2 recv:{:?}”,rx1.recv().unwrap());
});
child0.join();
child1.join();
child2.join();
在这里,我在一个循环中创建通道,将它们存储在一个向量中,对发送器重新排序,将它们存储在一个新的向量中,然后生成线程,每个线程都有自己的发送器-接收器(tx1/rx0、tx2/rx1等)对
const-NTHREADS:usize=8;
//创建n个通道
let频道:Vec=
(0..NTHREADS).into_iter().map(| | mpsc::channel()).collect();
//用于发送方创建环形拓扑的开关元组条目
让多个通道_环:Vec=(0..NTHREADS)
.into_iter()
.map(|i|{
(
通道[如果i
这不起作用,因为无法复制发送方来创建新向量。
但是,如果我使用refs(和发送方):
let mut channels\u ring:Vec=(0..NTHREADS)
.into_iter()
.map(|i|{
(
&通道[如果i
我无法生成线程,因为无法在线程之间安全地共享std::sync::mpsc::Sender
这不起作用,因为无法复制发送方来创建新向量。但是,如果使用引用(&S):
虽然发送方
确实无法复制,但它确实实现了克隆
,因此您始终可以手动克隆它。但是这种方法不适用于接收器
,它不是克隆
,而且还需要从向量中提取
第一个代码的问题是不能使用let foo=vec[i]
从非Copy
值的向量中只移动一个值。这将使向量处于无效状态,其中一个元素无效,随后对该元素的访问将导致未定义的行为。为此,Vec
需要跟踪哪些元素被移动了,哪些元素没有移动,这将给所有Vec
带来成本。因此,相反,Vec
不允许从中移出元素,让用户跟踪移动
将值移出Vec
的一种简单方法是将Vec
替换为Vec
,然后使用foo=vec[i]
替换为foo=vec[i].take().unwrap()
,它从vec[i]
中的选项中移动T
值(同时声明它不是None
),并在向量中保留None
,这是选项的有效变体。这是您第一次尝试以这种方式修改():
const-NTHREADS:usize=8;
让通道振铃:Vec={
让多个通道:Vec=(0..NTHREADS)
.into_iter()
.地图{
let(tx,rx)=mpsc::channel();
(一些(发送),一些(接收))
})
.收集();
(0..NTHREADS)
.into_iter()
.map(| rxpos |{
设txpos=if rxpos
发送方
s和接收方
s无法共享,因此您需要将它们移动到各自的线程中。这意味着从Vec
中删除它们,或者在迭代过程中使用Vec
——即使作为中间步骤,也不允许向量处于无效状态(带孔)。用迭代向量到iter
将通过使用它们来实现这一点
让发送方和接收方在一个周期内配对的一个小技巧是创建两个向量;一个发送方和一个接收方;然后旋转一个,这样每个向量中的相同索引将为您提供所需的对
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
fn main() {
const NTHREADS: usize = 8;
// create n channels
let (mut senders, receivers): (Vec<Sender<i32>>, Vec<Receiver<i32>>) =
(0..NTHREADS).into_iter().map(|_| mpsc::channel()).unzip();
// move the first sender to the back
senders.rotate_left(1);
let children: Vec<_> = senders
.into_iter()
.zip(receivers.into_iter())
.enumerate()
.map(|(i, (tx, rx))| {
thread::spawn(move || {
tx.send(i as i32).unwrap();
println!("thread {} sent: {}", i, i);
println!("thread {} recv: {:?}", i, rx.recv().unwrap());
})
})
.collect();
for child in children {
let _ = child.join();
}
}
使用std::sync::mpsc:{self,Receiver,Sender};
使用std::线程;
fn main(){
常数n:usize=8;
//创建n个通道
let(mut发送方、接收方):(Vec、Vec)=
(0..NTHREADS).into_iter().map(| | mpsc::channel()).unzip();
//将第一个发送器移到后面
发送器。向左旋转(1);
让子项:Vec=发送者
.into_iter()
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
fn main() {
const NTHREADS: usize = 8;
// create n channels
let (mut senders, receivers): (Vec<Sender<i32>>, Vec<Receiver<i32>>) =
(0..NTHREADS).into_iter().map(|_| mpsc::channel()).unzip();
// move the first sender to the back
senders.rotate_left(1);
let children: Vec<_> = senders
.into_iter()
.zip(receivers.into_iter())
.enumerate()
.map(|(i, (tx, rx))| {
thread::spawn(move || {
tx.send(i as i32).unwrap();
println!("thread {} sent: {}", i, i);
println!("thread {} recv: {:?}", i, rx.recv().unwrap());
})
})
.collect();
for child in children {
let _ = child.join();
}
}