Wednesday, January 15, 2014

FeedaMail: Comments for Sutter’s Mill

feedamail.com Comments for Sutter's Mill

Comment on GotW #7c Solution: Minimizing Compile-Time Dependencies, Part 3 by Herb Sutter

@Lachlan: It was because the comments were held for moderation, so they didn’t see each other’s comments. Then I approved them all, not wanting to quash anyone and crediting the first to point out the typos.

Read More »

Comment on Reader Q&A: Book recommendations by Mario Knezović

Design Patterns: “Head First Design Patterns” for getting into design patterns thinking. GoF book is the definitive authority. Gurus can skip the first book. The GoF book is outdated regarding C++11. For a consciousness-expanding view from a C++11 perspective check out Tobias Darm’s presentation “Effective GoF Patterns with C++11 and Boost” (not a book, but awesome anyway, even though a few code examples on the slides are incomplete): http://www.infoq.com/presentations/gof-patterns-c-plus-plus-boost

Concurrency: “C++ Concurrency in Action” and Herb’s articles.

Read More »

Comment on GotW #7c Solution: Minimizing Compile-Time Dependencies, Part 3 by Lachlan Easton

Why are so many people repeating the same things in comments? You would think once someone has pointed out that the #include has not been removed that it would become publicly known and not need further pointing out.

Read More »

Comment on GotW #95: Thread Safety and Synchronization by Bartosz Milewski

As it often happens in OO programming, there is some confusion about what is meant by “object”. From the point of view of concurrency, a mutex protecting an object protects the transitive closure of all the pointers in that data structure. But that’s probably not what most people understand as an object, so the problem of pointers (references) going out of an object arises. If these pointers point to data that is independently shared — meaning: not only through the parent object — then there’s need for additional synchronization. It’s cases like these that may lead to deadlocks, but that’s probably a topic for another GotW.

Read More »

Comment on GotW #95: Thread Safety and Synchronization by nosenseetal

btw thou shalt not return reference to a member variable… idk if that is answer to one of this questions but if it is not it should be added… it is extremly easy to forgett about that when you decide to mutexify your class by adding a lock_guard to ever method. :)

Read More »

Comment on GotW #7c Solution: Minimizing Compile-Time Dependencies, Part 3 by Lachlan Easton

Ohhhhhhhh. Well that makes too much sense. Never mind me.

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Casey

“So it's not like shared_ptr is not a fully internally synchronized type” Yes, it is exactly “like shared_ptr is not a fully internally synchronized type.” I think you doubled up on “not” in this clause.

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Daniel Hardman

I am uncomfortable with the wording of your first guideline, because it’s stated without a caveat. Reads (const operations) are safe IFF no writes are happening concurrently–but you state it as if reads can always be considered safe, without condition. This is also a reason why I don’t like the summary you gave about the meaning of “const” and “mutable” in one of your recent talks.

It seems to me that a clearer way to explain it would be: reads do not, in and of themselves, introduce any threading problems. Therefore, if reads are the only operations happening, you have thread safety. However, if writes are also happening, then the reads (not just the writes) also become unsafe. *Thread safety is not a characteristic of an individual operation; it is a characteristic of an overall usage pattern.* Thus, “read” or “const” does not mean “thread-safe”–it means “introducing no threading problems, but still vulnerable to vicitimization by them”.

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Herb Sutter

@Daniel: I’ve added the words “with each other” — better?

@Casey: Good eyes, second “not” removed, thanks!

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by mcmcc

Guideline #0: Prefer to not share data at all.

Its surprising how often this idea fails to occur to people…

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Bartosz Milewski

Herb, you keep using the word “own” without explaining it. When dealing with resource management, owning means being responsible for final disposal, and that’s not what you mean here, do you?

Read More »

Comment on GotW #7b Solution: Minimizing Compile-Time Dependencies, Part 2 by Rob Stewart

@mttpd

I regularly do what you argue against. I wish there was a file-scope using directive so I could make the header consistent with the implementation file. I do find the need to be explicit, in headers, frustrating, because I’d much rather use shorter names when there’s no ambiguity.

I use typedefs in headers (mostly in class definitions), namespace aliases, and using declarations along with using directives, so you’d probably dislike my code as a result. Despite all of that, however, I don’t see that this approach increases complexity. I’ll grant that one must examine context to know, with certainly, which vector some code means when it isn’t scope resolved, and I do find myself forgetting to switch to fully qualified names in headers when I copy a type from the implementation file. Nevertheless, I’d hate to encourage or, worse still, require full qualification in all or most contexts. After all, namespaces are given long names, in many cases, specifically to reduce conflicts and because there are tools to obviate the line noise.

Speaking of line noise, you noted that code is read more than written, so one shouldn’t be concerned with typing extra characters. That isn’t my reason for avoiding the fully qualified names. The extra characters on a line are usually not needed to increase code clarity. Indeed, I find that they normally detract from readability. You invoked Boost as disclaiming Herb’s assertion that “people just won't put up with” the long names. The problem is that Boost must use fully qualified names in its headers, but in no way does that impose the same on Boost users. (I use many Boost libraries and use all of the tools at my disposal to shorten names when possible.)

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Alb

Even just reading a const variable can raise a race condition in the particular case when you access a controler register. Even if the variable is (both volatile and) const qualified.

I am wondering if I did not more often face race condition in the ‘extended’ sense (interleaves problems) rather than the reader/writer concurrent scheme. The race condition has just been so much explained that most of time I see code with variable access protected (even with a ‘disable/enable-all-interrupts’ hammer) but without analysis of the entire design ands its hidden ‘logical’ dependency.
Nevertheless using the appropriate synchronisation construct is not trivial and thanks for giving us such wise and discerning advice.

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Herb Sutter

@Bartosz: I often said “owns or uses” to try to make it clear we’re talking about the code that creates/manipulates/manages/destroys the variable. If “owns” and “uses/owns” are unclear I’d be happy to consider suggestions — what would be better?

@mcmcc: Yes, but that’s beyond the scope of this particular GotW. Wait for it… :)

Read More »

Comment on GotW #96: Oversharing by sbohmann

1.a. because interdependencies between otherwise independent parts of the code arise – not only in the face of multiple threads but also in the face of – at first glance more innocent – coroutines.

1.b. because these interdependencies may manifest as side-effects of entirely unrelated things happening in other parts of code. Plus, these are often hard to find and almost always hard to debug when they emerge. Race conditions are but one popular example…

1.c. because wait states emerge that take up more and more time with increasing lock contention. Making data that is shared between vast parts of a project a source of lock contention can easily lead to a huge amount thereof. Throwing a vast number of threads at the problem won’t work because they always consume space (for their stacks, plus indirectly on the heap (yes, “free store” in C++)) and time because of the great price of context switches. Plus, making more threads wait all the time for the same resources wouldn’t help much in any case.

2.a. make copies. Defensive copying is not the brightest idea in most cases but may actually help if there are more or less outlandish reasons that make them the only feasible approach (like an existing code base that just can’t be adapted, or, in the worst case, political reasons).

2.b. use persistent collections plus immutable data objects, like custom classes, or const std::string etc. Immutable data is friendly to reference counting, and reference counting is well compatible with most of these non-circular tree-based persistent (i.e. immutable with low-cost copying) data structures. I really hope they will pop up in the STL as soon as possible so I can replace my home-brewn implementations (because the STL is ALWAYS more thoroughly tested :D)

Read More »

Comment on GotW #96: Oversharing by Guru of the Week 95 : Thread Safety and Synchronization | C++, Qt, OpenGL, CUDA

[…] Il a également posté les questions du prochain GotW : GotW #96: Oversharing. […]

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Guru of the Week 95 : Thread Safety and Synchronization | C++, Qt, OpenGL, CUDA

[…] GotW #95 Solution: Thread Safety and Synchronization. […]

Read More »

Comment on GotW #93 Solution: Auto Variables, Part 2 by C++11语言扩展:常规特性 - 博客 - 伯乐在线

[…] Herb Sutter: GotW #93: Auto Variables, Part 2 […]

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Marcel Wid

“A race condition occurs when two threads access the same shared variable, and at least one is a non-const operation (writer).”
“If a race condition occurs, your program has undefined behavior.”

I interpret these two statements that you mean the term “data race” in the terminology of the standard.

If this definition were right, then it would be impossible to write a data race free program. Because by your definition a properly synchronized access to a shared variable would also result in a data race and hence in undefined behavior. I think, the definition from the standard is quite readable:

“Two expression evaluations conflict if one of them modifies a memory location and the other one accesses or modifies the same memory location.”
“The execution of a program contains a data race if it contains two conflicting actions in different threads,
at least one of which is not atomic, and neither happens before the other.”

Read More »

Comment on GotW #96: Oversharing by JMK

Mimons dcqf´

Envoyé de mon iPhone

Read More »

Comment on GotW #96: Oversharing by StackedCrooked

  1a. - the logic is polluted with mutexes and locks. this reduces readability.    1b. - possible to forget to lock leading to data races        - possible deadlocks. for example:          - high-level code calls low-level code while holding the lock          - low level code invokes callback to high-level function which tries to lock      - possibility of lifetime bugs (object which is destroyed in one thread        while another thread is reading from it)              1c. - locking prevents parallelism    2a. - writer thread owns the object and reader receives copies.      - if your application has  a message loop then a thread can run in the        background and send updated copies to the main thread via "post" events        (concurrent_queues can be used to for a more general solution)          2b. - using techniques from (pure) functional programming languages where you        never change the object but always pass updated copies back and forth.                  3b. I'm not sure what you have in mind. But here a few wild guesses:      - maybe using software transactional memory? (not sure if transactions count        as external synchronization)      - perhaps a proxy type which stores a private copy of the real object? (state        changes could be communicated to other proxies using some kind of        messaging system.)  

Read More »

Comment on GotW #96: Oversharing by Sebastian Bohmann

3. if the variable is of a class type, not a pointer, the internal representation may be a reference counted smart pointer to an immutable value or persistent collection. Plus, the reference counted smart pointer should either be thread-safe, else it must be guarded in the assignment op + copy c’tor.

Just another variant on the pimpl idiom with a ref counting smart pointer :)

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by mcmcc

> @mcmcc: Yes, but that's beyond the scope of this particular GotW. Wait for it… :)

Perhaps what I’m noting here is that the GotW’s are coming the wrong order. The “Oversharing” GotW should come first because that (I presume ;) suggests the ideal solution. This GotW starts with “Well, here you are sharing stuff – how do you avoid problems” without discussing how/why you ended up in that situation in the first place.

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Bartosz Milewski

I think I’m confused because ownership may have specific meaning in the context of concurrency. People came up with ownership schemes to describe synchronization. I studied these things when we were designing D (here’s a blog I wrote back then: http://bartoszmilewski.com/2009/06/02/race-free-multithreading-ownership/ ). The “owner” in these schemes is the object responsible for locking. When you are talking about objects that might be connected under the covers, that would be a violation of ownership (and an invitation to deadlock). I think I would stick to “uses” or “has access to” rather than “owns” when talking about code.

Read More »

Comment on GotW #96: Oversharing by cartec69

3. If the shared variable can be completely internally synchronized in a lock-free manner, then it can neither contribute to data races nor introduce potential deadlock.

Read More »

Comment on GotW #96: Oversharing by Sebastian Bohmann

ad 3. in case a mutable datum is required that may be changed from different parts of a system, be it within the same thread or across multiple threads, opposed to just safely sharing values, which is easily done by choosing an appropriate technique as described above, it really gets more interesting :)

Such a capability demands a core requirement of your project for becoming a necessity.

And implementing it demands thinking about to what end it shall be implemented first. Software transactional memory is oft cited as a technological approach but that does not cover the complexities inherent to the situation from which the need usually emerges in the first place.

When there is a centrally stored value that requires manipulation from various places, various threads, and various sub-domains of a projects aim, it is usually not independent from other parts of a common business logic :)

Therefore, this case is in my honest opinion the hardest to phrase a general technological approach for and thus a bit out of reach of a discussion on a somewhat language- and platform-centric discussion ;)

Read More »

Comment on GotW #96: Oversharing by Ralph Tandetzky

Without looking at previous answers:

1. Why do mutable shared variables like some_obj make your code:
(a) more complex?

Because it means that in almost all cases there must be a mutex associated with the variable. Often other invariants need to be established in order to reason about the behaviour of some code. Different implementations of concurrent queues are classic examples of this.

(b) more brittle?

It is hard to reason about shared state because it implies interdependencies of different parts of a program. Therefore, the code and logic of the application is usually not found in one place which makes the code harder to reason about. Often, when extending the functionality of a component more state needs to be added and it must be decided whether to protect the new state with the same mutex as well.

(c) less scalable?

Sharing is the root of contention. When many different threads are fighting for one mutex then this may easily lead to a performance bottleneck. If a thread is holding a mutex half of the time in a tight loop, then having multiple threads trying to do the same thing will at most double the performance. But multithreading might even worsen performance. Therefore, mutexes should be held only during very short actions which make some work take effect. For example such a short action might be changing a pointer or incrementing or decrementing a counter, etc.

When programming for the strong exception guarantee the technique of the red line of often employed, where the actual work is done on the side (without side effects) in a first phase and in a second phase that work is committed by performing some non-throwing mutating operations which are usually cheap to perform (like a swap or a move). Often multithreaded code uses the same technique with the difference that the mutex is held during the commit phase. Designing the code that way can be a hard task. We get scalability at the price of brittleness and complexity.

2. Give an example of how the code that uses a mutable shared variable like some_obj can be changed so that the variable is:
(a) not shared.
(b) not mutable.

Simple. Make a copy. Since the concurrency revolution it is often better to avoid contention via references or pointers to shared objects but instead make copies. The function code_that_modifies() can be changed to have the signature

  	some_type code_that_modifies( some_type some_obj );  

That way an object can be moved into the function which might be cheaper and exception-safer. That very same object can also be moved out of the function as a return value. In an ideal case the function will have approximately the same performance as the original, if not even better. Better, I say? — Yes, because there’s less indirection!

A second technique on top of that is to replace a variable of some_type by a shared_ptr to a const some_type. The pointee is immutable, but the pointer can be changed in a commit action while holding a mutex as mentioned above. This shortens the time the mutex is held. If the shared_ptr is the only variable protected by the mutex, then we might even be tempted to use atomic operations on shared_ptr as provided by the standard library and go without mutex.

These techniques might not always be practical, because copying and moving might be expensive or impossible.

3. Let's say we're in a situation where we can't apply the techniques from the answers to #2, so that the variable itself must remain shared and apparently mutable. Is there any way that the internal implementation of the variable can make the variable be physically not shared and/or not mutable, so that the calling code can treat it as a logically shared-and-mutable object yet not need to perform external synchronization? If so, explain. If not, why not?

Sorry, Herb, I don’t understand what you have in mind with this question. What do you mean by *physically*? I’m thinking of thread-local storage in order to get variables that are physically not shared yet behave like one object (in object oriented design I have not found thread-local storage very helpful though). Alternatively, I’m thinking of a copy-on-write template class which makes sure that the data is immutable unless there is only one unique reference to it.

Otherwise, I would say, it’s not possible because I’m out of ideas. ;)

Read More »

Comment on GotW #96: Oversharing by sbohmann

P.S. please forgive my orthography – it makes me cringe to read my posts but I’m writing on my iPad with autocorrect turned off because turning it off looked like a a smart idea at some point ;)

Read More »

Comment on GotW #96: Oversharing by sbohmann

ad my response to 3.: such a mutable, but thread-safe and internally immutable and internally ref counted data wrapper can very easily be made immutable by making it const, e.g. for holding it in a persistent collection. it’s possible because its mutability is VERY shallow :)

Deeper mutability would in almost all cases be a show stopper here.

About std::string: when the part of a persisten collection that holds a string instance is modified (i.e. replaced) in the course of a persistent update (i.e. creation of an updated instance), the string will be copied.

therefore, if strings tends to be large in such a scenario, it may make sense to wrap it as in my response to 3., especially if mutability is NOT required – the wrapped string then behaves somewhat like a Java or C# string, i.e., its value is immutable (the embedded reference only if const), and copying it is practically free, which is just what persistent collections crave when it comes to their elemt types :)

Read More »

Comment on GotW #7c Solution: Minimizing Compile-Time Dependencies, Part 3 by Rob Stewart

@Alexandre Chassany

Refer to the solution for #7a, including Sebastian Redl’s comment, which discussed eliminating the E.h include directive because E was used only as an argument and a return type. B is now used in exactly the same ways.

Read More »

Comment on GotW #95 Solution: Thread Safety and Synchronization by Marcel Wid

@Herb: You added the word “concurrently” to the definition of race condition (aka data race). I’m afraid, but as the definition now stands, it is as wrong as it was before. “Concurrent access” doesn’t necessarily introduce a data race (at least if you use the term “concurrent access” as in the spec). Here is a quote from §20.7.2.5/1:

“Concurrent access to a shared_ptr object from multiple threads does not introduce a data race if the access is done exclusively via the functions in this section and the instance is passed as their first argument.”

I know that it is almost impossible to give a definition of “data race” in one line. Here is a suggestion:

“A race condition occurs when two different threads access the same shared variable and at least one of them is a store (write) and they may be executed at the same time (they may interleave).”

Read More »

Comment on GotW #92 Solution: Auto Variables, Part 1 by C++11语言扩展:常规特性 | zengine

[…] Herb Sutter: GotW #92: Auto Variables, Part 1 […]

Read More »
 
Delievered to you by Feedamail.
Unsubscribe

No comments:

Post a Comment