4 ms·
The C++ example given in the article is not correct. In C++ a mutex can wrap the object being protected.
by mrlonglong 11mo ago
The C++ example given in the article is not correct.
In C++ a mutex can wrap the object being protected.
- tialaramex 11mo agoAlthough there are owning mutexes for C++ the C++ standard library does not provide such a thing. So the std::mutex used in the example is not an owning mutex and that example works and does what was described. One reason not to provide the owning mutex in C++ is that it isn't able to deliver similar guarantees to Rust because its type system isn't strong enough. Rust won't let you accidentally keep a reference to the protected object after unlocking, C++ will for example.
- questioner8216 11mo agoI am not very familiar with C++'s API, but I believe that you are right that the C++ example in the article is incorrect, though for a different reason, namely that RAII is supported also in C++. In C++, a class like std::lock_guard also provides "Automatic unlock". AFAICT, the article argues that only Rust's API provides that. { const std::lock_guard<std::mutex> lock(mtx); account.balance -= amount; account.transaction_count++; } // Automatically unlocked.
- aw1621107 11mo ago> In C++, a class like std::lock_guard also provides "Automatic unlock". AFAICT, the article argues that only Rust's API provides that. The issue isn't automatic unlocking. From the article: > The problem? Nothing stops you from accessing account without locking the mutex first. The compiler won’t catch this bug. i.e., a C++ compiler will happily compile code that modifies `account` without taking the lock first. Your lock_guard example suffers from this same issue. Nothing in the C++ stdlib provides an API that makes it impossible to access `account` without first taking the lock, and while you can write C++ classes that approximate the Rust API you can't quite reach the same level of robustness without external help.
- questioner8216 11mo agoThat is a different topic from what I wrote about. The article wrote: > Automatic unlock: When you lock, you receive a guard. When the guard goes out of scope, it automatically unlocks. No manual cleanup needed. And presented Rust as being different from C++ regarding that, and the C++ example was not idiomatic, since it did not use something like std::lock_guard. I have not addressed the rest of your comment, since it is a different topic, sorry.
- aw1621107 11mo agoFair point with respect to the separate topic. My apologies. As for the automatic cleanup bit, perhaps the article is trying to focus purely on the mutex types themselves? Or maybe they included the "when you lock" bit to emphasize that you can't forget to unlock the mutex (i.e., no reliance on unenforced idioms). Hard to say given the brevity/nature of the section, and in the end I think it's not that much of a problem given the general topic of the blogpost.
- questioner8216 11mo agoWhen comparing languages, posting unidiomatic code, and then making claims based on that unidiomatic code, is generally not fair nor correct.
- aw1621107 11mo agoThat's true if the claims hinge on said unidiomatic code. As I said, it's not clear to me that that is the case here.
- questioner8216 11mo agoIt seems completely clear. He first gives unidiomatic C++ code, then next gives idiomatic Rust code, and differentiates the two based on the code snippets. It is a mistake on his part, and I do not see how it could reasonably be viewed otherwise. It is not a huge mistake, but it is still a clear mistake.
- mrlonglong 11mo ago#include <iostream> #include <mutex> #include <thread> class SharedResource { private: int value; std::mutex mtx; public: SharedResource() : value(0) {} void setValue(int newValue) { std::lock_guard<std::mutex> guard(mtx); value = newValue; } int getValue() { std::lock_guard<std::mutex> guard(mtx); return value; } }; void threadFunction(SharedResource& resource) { resource.setValue(42); std::cout << "Value: " << resource.getValue() << std::endl; } int main() { SharedResource resource; std::thread t1(threadFunction, std::ref(resource)); std::thread t2(threadFunction, std::ref(resource)); t1.join(); t2.join(); return 0; }
- mrlonglong 11mo agoThis prevents access to the variable being protected by the mutex.