Safe testing with mutable global

Here is a solution for leetcode problem 374. But I think it's not always correct on multi thread testing and don't know how to make it right.

The reason is: On each test, we write RwLock and drop, then run the guess_number function, which call guess function, which read RwLock. In the middle of one test, the value in RwLock may be potentially changed by another test.

How to make a mutable global, that can be locked in current thread, then only functions in current thread can read write it. Or can i transfer a RwLock write into read atomatically, so there's is no gap for other thread to acquire it.

use std::sync::RwLock;

static TARGET: RwLock<i32> = RwLock::new(0);
fn guess(n: i32) -> i32 {
    let t = TARGET.read().unwrap();
    match n.cmp(&t) {
        std::cmp::Ordering::Less => 1,
        std::cmp::Ordering::Equal => 0,
        std::cmp::Ordering::Greater => -1,
    }
}

struct Solution;
impl Solution {
    fn guess_number(n: i32) -> i32 {
        let mut l = 1;
        let mut r = n;
        while l <= r {
            let m = l + (r - l) / 2;
            match guess(m) {
                -1 => r = m - 1,
                1 => l = m + 1,
                _ => return m,
            }
        }
        -1
    }
}
#[cfg(test)]
mod test {
    use super::*;

    fn test(n: i32, pick: i32) {
        let mut t = TARGET.write().unwrap();
        *t = pick;
        drop(t);
        let out = Solution::guess_number(n);
        assert_eq!(out, pick);
    }

    #[test]
    fn test1() {
        test(10, 6);
    }
    #[test]
    fn test2() {
        test(1, 1);
    }
    #[test]
    fn test3() {
        test(2, 1);
    }
}

(Playground)

I was going to comment about how this is a terrible use of global state... then realised you probably have to use the interface as-is without changing it. Which probably makes this a terrible but unavoidable use of global state. :smiley:

You probably want thread_local!. Also, it will probably be a little simpler to use an AtomicI32, since atomics don't need locking.

I'll second the suggestion to use thread_local here. However for the abstract question of

Then, the mutexes offered by parking_lot offer an option, the ReentrantMutex (which you can pair with a RefCell inside it to still have mutability). As long as the outer function holds on to the ReentrantMutexGuard only functions in the same thread can (re-entrantly) acquire access to it.

parking_lot also has options for this. Its RwLock has api to downgrade WriteGuards to ReadGuards.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.