pubfnmain() -> i32 {
let start = get_time();
letmut v = Vec::new();
for _ in0..THREAD_COUNT {
v.push(thread_create(f asusize, 0) asusize); // f函数是线程主体
}
letmut time_cost = Vec::new();
for tid in v.iter() {
time_cost.push(waittid(*tid));
}
println!("time cost is {}ms", get_time() - start);
assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); //比较累计值A0
}
实践步骤
全局变量累加问题的多线程应用 race_adder.rs
unsafefnf() -> ! {
letmut t = 2usize;
for _ in0..PER_THREAD {
let a = &mut A as *mutusize; // “缓慢执行”A=A+1 let cur = a.read_volatile(); // “缓慢执行”A=A+1for _ in0..500 { t = t * t % 10007; } // 增加切换概率
a.write_volatile(cur + 1); // “缓慢执行”A=A+1
}
exit(t asi32)
}
实践步骤
全局变量累加问题的多线程应用 race_adder.rs
>> race_adder
time cost is 31ms
Panicked at src/bin/race_adder.rs:40, assertion failed: `(left == right)`
left: `15788`,
right: `16000`
[kernel] Aborted, SIGABRT=6
每次都会执行都会出现Race Condition(竞争条件)!
实践步骤
基于原子操作的全局变量累加问题的多线程应用 race_adder_atomic.rs
unsafefnf() -> ! {
for _ in0..PER_THREAD {
while OCCUPIED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err() { yield_(); } // 基于CAS操作的近似spin lock操作let a = &mut A as *mutusize; // “缓慢执行”A=A+1 let cur = a.read_volatile(); // “缓慢执行”A=A+1 for _ in0..500 { t = t * t % 10007; } // 增加切换概率
a.write_volatile(cur + 1); // “缓慢执行”A=A+1
OCCUPIED.store(false, Ordering::Relaxed); // unlock操作
}
...
实践步骤
基于原子操作的全局变量累加问题的多线程应用 race_adder_atomic.rs
>> race_adder_atomic
time cost is 29ms
>> race_adder_loop
可以看到,执行速度快,且正确。
实践步骤
基于互斥锁的多线程应用 race_adder_mutex_[spin|block]
unsafefnf() -> ! {
letmut t = 2usize;
for _ in0..PER_THREAD {
mutex_lock(0); //lock(id)let a = &mut A as *mutusize; // “缓慢执行”A=A+1 let cur = a.read_volatile(); // “缓慢执行”A=A+1 for _ in0..500 { t = t * t % 10007; } // 增加切换概率
a.write_volatile(cur + 1); // “缓慢执行”A=A+1
mutex_unlock(0); //unlock(id)
}
exit(t asi32)
}
实践步骤
基于互斥锁的全局变量累加问题的多线程应用 race_adder_mutex_spin
>> race_adder_mutex_spin
time cost is 249ms
# 执行系统调用,且进行在就绪队列上的取出/插入/等待操作
基于互斥锁的全局变量累加问题的多线程应用 race_adder_mutex_block
>> race_adder_mutex_blocking
time cost is 919ms
# 执行系统调用,且进行在就绪队列+等待队列上的取出/插入/等待操作
pubfnmain() -> i32 {
// create semaphoresassert_eq!(semaphore_create(0) asusize, SEM_SYNC);
// create threadslet threads = vec![
thread_create(first asusize, 0),
thread_create(second asusize, 0),
];
// wait for all threads to completefor thread in threads.iter() {
waittid(*thread asusize);
}
...
实践步骤
基于信号量的多线程应用 sync_sem
unsafefnfirst() -> ! {
sleep(10);
println!("First work and wakeup Second");
semaphore_up(SEM_SYNC);
exit(0)
}
unsafefnsecond() -> ! {
println!("Second want to continue,but need to wait first");
semaphore_down(SEM_SYNC);
println!("Second can work now");
exit(0)
}
实践步骤
基于信号量的多线程应用 sync_sem
>> sync_sem
Second want to continue,but need to wait first
First work and wakeup Second
Second can work now
sync_sem passed!
unsafefnsecond() -> ! {
println!("Second want to continue,but need to wait A=1");
mutex_lock(MUTEX_ID);
while A == 0 {
println!("Second: A is {}", A);
condvar_wait(CONDVAR_ID, MUTEX_ID);
}
mutex_unlock(MUTEX_ID);
println!("A is {}, Second can work now", A);
exit(0)
}
实践步骤
基于互斥锁和条件变量的多线程应用 test_condvar
unsafefnfirst() -> ! {
sleep(10);
println!("First work, Change A --> 1 and wakeup Second");
mutex_lock(MUTEX_ID);
A = 1;
condvar_signal(CONDVAR_ID);
mutex_unlock(MUTEX_ID);
exit(0)
}
实践步骤
基于互斥锁和条件变量的多线程应用 test_condvar
>> test_condvar
Second: A is 0
First work, Change A --> 1 and wakeup Second
A is 1, Second can work now