玩while (line != null)
{
for (int i = 0; i < line.length(); i++)
{
if (!Character.isWhitespace(line.charAt(i)))
count ++;
line = br.readLine();
}
System.out.println(count);
}
时出现意外结果。我知道我不敢相信自己的Condvar
不会早起,但是就我而言,似乎始终没有我的一次起床。给出以下示例代码:
wait()
我只会让前八个线程退出循环:
use std::sync::{Arc, Mutex, Condvar};
use std::{
thread,
time
};
fn main() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pause = time::Duration::from_secs(1);
for id in 0..10 {
let pair2 = pair.clone();
thread::spawn(move|| {
let &(ref lock, ref cvar) = &*pair2;
let lock = lock.lock().unwrap();
let _ = cvar.wait(lock).unwrap();
println!("Thread {} done!", id);
});
}
// Wait for the thread to start up.
let &(ref _lock, ref cvar) = &*pair;
for _ in 0..10 {
thread::sleep(pause);
cvar.notify_one();
}
}
如果我将第二个循环的计数增加到11,则实际上会唤醒所有9个循环。
我在Thread 0 done!
Thread 1 done!
Thread 2 done!
Thread 3 done!
Thread 4 done!
Thread 5 done!
Thread 6 done!
Thread 7 done!
Thread 8 done!
和wait()
上都对the documentation进行了仔细检查,但这里出了什么问题并不明显。
有什么想法吗?这是错误还是我没有做对的事情?
答案 0 :(得分:4)
根据the documentation of std::thread::spawn
,您的主线程不等待工作线程完成:
[…]子线程可能会超过父线程(,除非父线程是主线程;整个过程在主线程结束时终止。)
(强调是我的)
由于您的程序在最后一个notify_one
之后立即终止,因此工作线程可能会在打印值之前被杀死。
当您循环11次时,第10个notify_all
之后会休眠1 s,这意味着最新的工作线程可能会完成其工作。
该问题的常见解决方案是按照sn99's answer收集JoinHandle
返回的spawn
,并等待它们。
答案 1 :(得分:1)
将代码更改为:
use std::sync::{Arc, Condvar, Mutex};
use std::{thread, time};
fn main() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pause = time::Duration::from_secs(1);
// Create a vector of `JoinHandle`
let mut thread_handles = Vec::new();
for id in 0..10 {
let pair2 = pair.clone();
// Push JoinHandle in the vector
thread_handles.push(thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair2;
let lock = lock.lock().unwrap();
let _ = cvar.wait(lock).unwrap();
println!("Thread {} done!", id);
}));
}
// Wait for the thread to start up.
let &(ref _lock, ref cvar) = &*pair;
for _ in 0..10 {
thread::sleep(pause);
cvar.notify_one();
}
// Wait for all threads to complete before exiting `main`
// handles is of type JoinHandle
for handles in thread_handles {
handles.join().unwrap();
}
}
join
方法等待所有线程完成。这是必要的,因为即使其他线程仍在运行,Rust程序也会在主程序返回后立即退出。