3 ms·
Reference counted copy-on-write strings are little landmines just waiting to blow your leg off should you venture into multi-threaded territory. If you use cop
by adamtj 12y ago
Reference counted copy-on-write strings are little landmines just waiting to blow your leg off should you venture into multi-threaded territory.
If you use copies of such a string in multiple different threads, you may find that simply creating a new copy of the original string or any of its subsequent copies can cause an incorrect reference count which will trigger a double-free and a segfault at some later time, possibly long after all non-main threads have ended.
You can't even lock all accesses to a string with a simple mutex. You have to also lock all descendant and ancestor copies, including all temporary copies, as when passing by value to a function. A COW string is basically a pointer to an internal shared data structure. You need to lock accesses to the shared structure, not the pointers to it, and you can only do that internally.
The only way to reliably use such a string with multiple threads is to make the internal reference count and buffer manipulations thread-safe. It may save you some allocations and copies, but the thread safety will slow things down. How much, I don't know. I wouldn't be surprised if thread-safe copy-on-write is slower than copy-always.
- kibwen 12y agoThis is where Rust is worth mentioning: its Rc smart pointer will statically prevent multiple threads from accessing the inner value, while its Arc (atomic reference counting) smart pointer will let you share the value while using atomic operations to adjust the refcount, same as C++'s shared_ptr. Rust's move semantics by-default also mean fewer refcount adjustments overall, since you can transfer ownership instead. There's also a neat new copy-on-write smart pointer in the stdlib, though I have no experience with it yet: http://doc.rust-lang.org/std/borrow/enum.Cow.html http://doc.rust-lang.org/std/borrow/enum.Cow.html
- humanrebar 12y agoYes, COW mutable strings is problematic. It makes more sense to have immutable COW strings, so locking for access isn't a concern. Of course, C++ doesn't have proper immutable data, so a carefully designed interface would be needed. That's not to say it's a perfect solution. As far as incorrect reference counts, that's a quality of implementation issue. In a truly multithreaded environment, you'd use locks or atomics to ensure thread safety. In other words, if you have a nice wrapper around a shared_ptr<vector<char const> const>, I don't think most of what you wrote above really applies anymore. But, again, it would be even better if C++ had a proper concept of immutability.