You'll need to wrap it in a struct or other type and impl Send for that type:
struct Foo(*mut i32);
unsafe impl Send for Foo {}
This requires unsafe because you must do your own synchronization to prevent data races. You may want to use types like AtomicI32 or Mutex instead, if you don't have some other synchronization mechanism handy.
Because in my toy code, sometimes it doesn't need to check or lock, only one place would modify the value, and all other places are reading the value. I assume Atomic would also lock the value right?
It might also help you to note that the pattern of wrapping a single field in a struct like that has the name newtype (the term can also be used to refer to the wrapper type itself), and it's free at runtime in the sense of imposing no memory overhead.
This is in stark contrast to e.g. Java where every type definition carries with it a nonzero runtime penalty.
That's not a valid reason for not using synchronization primitives. This can still lead to all sorts of nasty bugs, like one thread seeing the updated value but not the other.
No, the stdlib guarantees that if an atomic type is available on the platform you're compiling to then it is lock-free. std::sync::atomic - Rust