There is no overload of Thread.VolatileWrite which takes a String argument. The only reference type supported is Object.
Because VolatileWrite is updating the variable str and Option Strict is On the compiler complains because in theory VolatileWrite could attempt to write a value to that variable which is not of type String (the compiler only sees that it might write any Object). In fact, as the VolatileWrite method also only takes a String you could write code which would attempt to do this. It would fail for reasons beyond the scope of this question.
When you wrap the expression in a COjb/CType/DirectCast expression (really anything with parenthesis) then the variable is no longer considered a variable but a value - it's treated the same way as if you'd just type a string literal there. Since values don't have storage locations the ByRefness of VolatileWrite is ignored which means it no longer writes which means it can no longer write a bad value which means the compiler doesn't need to warn anymore.
To get the behavior you want with a string type variable use the System.Threading.Thread.MemoryBarrier method before your writes and after your reads. See this thread for additional information: How do I specify the equivalent of volatile in VB.net?