在多个线程中变异共享的可变变量

时间:2015-11-03 13:04:36

标签: multithreading rust

我想在多个线程中更改可变变量。我知道这不是线程安全的,但我想知道Rust编译器将如何处理它。所以我使用范围的map函数来生成子线程:

use std::thread;

fn break_law(value: &mut i32) {
    *value += 20;
}

fn main() {
    let mut x = 10;

    let handles = (0..10).map(|| {
        thread::spawn(move || {
        break_law(&mut x);
        println!("{:?}", x);
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}

但是我收到了一个错误:

break_law1.rs:10:24: 15:4 error: type mismatch: the type `[closure@break_law1.rs
:10:28: 15:3 x:_]` implements the trait `core::ops::FnMut<()>`, but the trait `c
ore::ops::FnMut<(_,)>` is required (expected tuple, found ()) [E0281]
break_law1.rs:10        let handles = (0..10).map(|| {
break_law1.rs:11                thread::spawn(move || {
break_law1.rs:12                        break_law(&mut x);
break_law1.rs:13                        println!("{:?}", x);
break_law1.rs:14                })
break_law1.rs:15        }).collect();
break_law1.rs:10:24: 15:4 help: run `rustc --explain E0281` to see a detailed ex
planation
break_law1.rs:10:24: 15:4 error: type mismatch: the type `[closure@break_law1.rs
:10:28: 15:3 x:_]` implements the trait `core::ops::FnOnce<()>`, but the trait `
core::ops::FnOnce<(_,)>` is required (expected tuple, found ()) [E0281]
break_law1.rs:10        let handles = (0..10).map(|| {
break_law1.rs:11                thread::spawn(move || {
break_law1.rs:12                        break_law(&mut x);
break_law1.rs:13                        println!("{:?}", x);
break_law1.rs:14                })
break_law1.rs:15        }).collect();
break_law1.rs:10:24: 15:4 help: run `rustc --explain E0281` to see a detailed ex
planation
break_law1.rs:15:5: 15:14 error: type mismatch: the type `[closure@break_law1.rs
:10:28: 15:3 x:_]` implements the trait `core::ops::FnMut<()>`, but the trait `c
ore::ops::FnMut<(_,)>` is required (expected tuple, found ()) [E0281]
break_law1.rs:15        }).collect();
                           ^~~~~~~~~
break_law1.rs:15:5: 15:14 help: run `rustc --explain E0281` to see a detailed ex
planation
break_law1.rs:18:6: 18:14 error: the type of this value must be known in this co
ntext
break_law1.rs:18            h.join().unwrap();
                            ^~~~~~~~
break_law1.rs:17:2: 19:3 note: in this expansion of for loop expansion
error: aborting due to 4 previous errors

根据上面的信息,我得到该范围的map函数定义是这样的:

// Creates a new iterator that will apply the specified function to each
// element returned by the first, yielding the mapped element instead.
fn map<B, F>(self, f: F) -> Map<Self, F> 
    where F: FnMut(Self::Item) -> B

这看起来很奇怪,但我该如何纠正呢?为什么?

2 个答案:

答案 0 :(得分:0)

map的类型签名是说类型参数(F)是一个闭包(FnMut),传递一个参数是迭代器产生的类型((Self::Item))并返回B-> B)。您遗失的部分是参数:它必须是.map(|x| { ... })而不是.map(|| { ... })

如果您不关心参数的值,可以使用.map(|_| { ... })模式忽略它来编写_,或者.map(|_i| { ... }),其中前导{{1}是一个约定,表示变量意图未使用(它使编译器对未使用变量的正常警告静音)。

FWIW,错误消息有点长,但确实包含以下信息:

_

我已经设置换行符来强调差异:编译器抱怨你传递给type mismatch: the type `[closure@break_law1.rs:10:28: 15:3 x:_]` implement the trait `core::ops::FnMut<()>`, but the trait `core::ops::FnMut<(_,)>` is required 的闭包没有参数(map),当它实际上想要一个拿一个(FnMut<()>FnMut<(_,)>表示尚未获得足够信息以进行完全推断的类型参数。

答案 1 :(得分:0)

顺便说一句,即使修复了如上所示的参数编号问题,也无法获得所需的行为。代码将成功编译,因为每个线程都会收到变量x副本,只要Rust中的整数类型实现Copy特征。

我认为正确的例子应如下所示:

fn break_law(value: &mut i32) {
    *value += 20;
}

fn main() {
    let mut x = 10;
    let ref_x = &mut x;

    let handles: Vec<_> = (0..10).map(|_| {
        thread::spawn(move || {
            break_law(ref_x);
            println!("{:?}", x);
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}