I know that data race is a UB in Rust, and I wonder how to write a "not so synchronous" multi-thread application in Rust.
By "not so synchronous", I mean that thread A needs to tell thread B to stop doing something, but it is not required B to stop doing so immediately. The rough model is like
Thread B is doing some performance critical jobs, and the standard way is to make stop_flag a mutex or an atomic bool. However, the synchronous check in each loop is unnecessary. Even though A makes stop_flag STOP, B can still run a little rounds, it's OK it stops in a best effort.
What is the best way to write this logic in Rust? Can we write one without UB?
Rust is not so different. You can use an AtomicBool. Or are you saying you already know how to do this in Rust, and you're looking for other ways?
One special case: If you have a thread that is processing requests it receives over a channel, there is a pattern where the receiving end of the channel reports an error when all senders have been dropped and the channel is empty. So the receiver thread simply exits its loop when it sees this error, since it means no more requests will be sent.
I do know the Rust way to do the standard atomic bool. What I mean is the synchronous thing is unnecessary for my situation, and I am looking forward to something that doesn't involve synchronous primitives but not UB.
I don't understand. There is no synchronous way to safely stop a system thread. Checking an AtomicBool at the top of the thread's main loop is an async solution.
Oh, by "synchronous primitives" do you mean "synchronization primitives"? Some sort of synchronization between threads is the only way to safely stop a thread.
If you want to perform less synchronization (for performance reasons), you can check the atomic flag every N loop iterations rather than every iteration.
You can also use Relaxed ordering when updating and checking the atomic flag. This allows the processor to lazily communicate the change to the flag to the other thread, rather than doing so ASAP.
Sorry for the ambiguity. Let me explain it more concretely.
In the situation I mentioned above, thread B's loop requires the performance instead of accuracy. When thread A wants the thread B to stop loop, it's OK that thread B can do one or more rounds until it actually stop the loop.
If we do not care about UB, the static variable way is adequate: A mutate the static to be STOP, and even though there is race condition where B may still get origin stop_flag value after A changes it, in one or more rounds after, the B can get the changed value after all, and stops the loop.
In this implementaion, there is no synchronization primitives in the loop of B, thus has better performance than the atomic bool or mutex solution. However, this implementaion is UB of course, and I wonder if there is a UB-free way to achieve this.
Using an atomic with Relaxed ordering is the closest you can get (that I know of, of course). The behavior is somewhat different on different types of CPUs. But in each case, this gives the CPU the most latitude for lazily communicating the change, while still doing it "eventually".