Comment by mehrdadn
7 years ago
"Just admit" what? That applying volatile to an object and casting that away like with the flag_ example is UB? Yeah, I that's UB. It also wasn't the point of the article, and the use of volatile required for the technique the article is what actually matters, which isn't UB.
Can we step back for a second?
Go back to my top comment. Why did I even post this article in the first place? The point was that "volatile-correctness" is (basically) awesome, and it's hard to get something like it in other languages. This article is where the idea originated from, so I linked to it. i.e.: "There's something called volatile-correctness, which you can learn about by reading this article." The point was not "read this article and blindly sprinkle volatile across your codebase in exactly the same manner and you'll magically get thread safety".
What were you supposed to take away from the article? The idea of volatile-correctness, the idea that you can use a locking pointer to regulate multithreaded access to a class's methods. The idea that volatile acts as a helpful type annotation in this regard, independently of its well-known effects on primitive objects. You can apply it easily without ever marking objects as volatile, like I just showed you in that example. Yet somehow instead of actually extracting the fundamental concepts and ideas from the article, you and everyone else here are trashing it by insisting that the only possible way anyone can read that article is a naive verbatim copy-paste of its text from 2001 to 2019...? Why?
> If you can agree with that, then maybe you can present a related technique, different to the one in the article, which uses volatile in a useful way.
But omitting a couple volatiles doesn't make it a different technique! You just skip the incorrect uses of volatile. The technique is the same..
"Just admit" that the stuff in the article is UB, because you were going around badgering people to point out the UB, and because your last post demands: "Right now we need to get the UB-ness claims out of the way. Once we agree it's correct in the first place..."
So yes, let's get the UB claims out of the way - but agreeing that it's UB. Not just the flag_ example, but with the LockingPtr example that is the "point" of the article.
> you and everyone else here are trashing it
To be clear, I'm not really "trashing" the article. It's a relic of its time. I am trashing the idea that it's somehow a good introduction to any clever MT technique today.
> by insisting that the only possible way anyone can read that article is a naive verbatim copy-paste of its text from 2001 to 2019...? Why?
I explained it earlier: because the article has too many flaws to be a clean illustration of the technique. It starts with UB, ends with UB, makes wrong assertions about the purpose of volatile, etc.
Again, I agree there might be a glimmer of something here - but this article isn't the way to show it. The reaction you got was expected and fine. I can imagine a different article, written today, without the claims about the purpose of volatile, without the flag example, without the UB of casting away volatile from volatile objects, acknowledging the existence of std::atomic and how this technique complements or replaces it. That could be useful.
I looked at your example, and yes, I see the potential if you want to have an object with a thread-safe and non-threadsafe interface split like that (or really any split: you can overload volatile like that for any type of access control where you can cleanly divide the functions like that). It has the unfortunate side effect that volatile is not for that, and it implicitly makes all your members volatile and hence may pessimize code generation. I guess it doesn't matter that much if all the volatile functions follow the pattern of immediately shelling out to a non-volatile function though.
Maybe someone should write a more modern version of the article, I don't know.
I would also not expect it to pessimize code generation, since the final dereference should always be of a non-volatile pointer, though I suppose an optimizer bug might make it behave otherwise.
You can combine it with atomic, they're not substitutes. It could let you implement two versions of an algorithm: a lock-free multithreaded one, along with a single-threaded one that uses relaxed accesses (or even fully non-atomic accesses, had C++ allowed that). And then you'd auto-dispatch on the volatile modifier. The possibilities are really endless; I'm sure the limiting factor here is our imagination.
I've thought about the other types of split for a long time too, and I haven't managed to come up with other compelling use cases, even though I also feel they should exist. It would be interesting if someone could come up with one, because the ability to have commutative tags on a type seems really powerful.