This commit is contained in:
Andrew Pardoe 2016-08-15 11:48:38 -07:00
commit 3dcc0e6976

View File

@ -10760,7 +10760,7 @@ the same memory. Concurrent programming is tricky for many reasons, most
importantly that it is undefined behavior to read data in one thread after it importantly that it is undefined behavior to read data in one thread after it
was written by another thread, if there is no proper synchronization between was written by another thread, if there is no proper synchronization between
those threads. Making existing single-threaded code execute concurrently can be those threads. Making existing single-threaded code execute concurrently can be
as trivial as adding `std::async` or `std::thread` strategically, or it can be as trivial as adding `std::async` or `std::thread` strategically, or it can
necessitate a full rewrite, depending on whether the original code was written necessitate a full rewrite, depending on whether the original code was written
in a thread-friendly way. in a thread-friendly way.
@ -10939,7 +10939,7 @@ Help the tools:
##### Reason ##### Reason
If you don't share writable data, you can't have a data race. If you don't share writable data, you can't have a data race.
The less sharing you do, the less chance you have to forget to synchanize access (and get data races). The less sharing you do, the less chance you have to forget to synchronize access (and get data races).
The less sharing you do, the less chance you have to wait on a lock (so performance can improve). The less sharing you do, the less chance you have to wait on a lock (so performance can improve).
##### Example ##### Example
@ -10965,7 +10965,7 @@ The less sharing you do, the less chance you have to wait on a lock (so performa
// ... // ...
} }
Without those `const`s, we would have to review every asynchroneously invoked function for potential data races on `surface_readings`. Without those `const`s, we would have to review every asynchronously invoked function for potential data races on `surface_readings`.
##### Note ##### Note
@ -10981,7 +10981,7 @@ No locking is needed: You can't have a data race on a constant.
##### Reason ##### Reason
A `thread` is a implementation concept, a way of thinking about the machine. A `thread` is an implementation concept, a way of thinking about the machine.
A task is an application notion, something you'd like to do, preferably concurrently with other tasks. A task is an application notion, something you'd like to do, preferably concurrently with other tasks.
Application concepts are easier to reason about. Application concepts are easier to reason about.
@ -11072,7 +11072,7 @@ Concurrency rule summary:
* [CP.27: Use plain `std::thread` for `thread`s that detach based on a run-time condition (only)](#Rconc-thread) * [CP.27: Use plain `std::thread` for `thread`s that detach based on a run-time condition (only)](#Rconc-thread)
* [CP.28: Remember to join scoped `thread`s that are not `detach()`ed](#Rconc-join) * [CP.28: Remember to join scoped `thread`s that are not `detach()`ed](#Rconc-join)
* [CP.30: Do not pass pointers to local variables to non-`raii_thread's](#Rconc-pass) * [CP.30: Do not pass pointers to local variables to non-`raii_thread's](#Rconc-pass)
* [CP.31: Pass small amounts of data between threads by value, reather by reference or pointer](#Rconc-data) * [CP.31: Pass small amounts of data between threads by value, rather than by reference or pointer](#Rconc-data)
* [CP.32: To share ownership beween unrelated `thread`s use `shared_ptr`](#Rconc-shared) * [CP.32: To share ownership beween unrelated `thread`s use `shared_ptr`](#Rconc-shared)
* [CP.40: Minimize context switching](#Rconc-switch) * [CP.40: Minimize context switching](#Rconc-switch)
* [CP.41: Minimize thread creation and destruction](#Rconc-create) * [CP.41: Minimize thread creation and destruction](#Rconc-create)
@ -11215,7 +11215,7 @@ If, as it is likely, `f()` invokes operations on `*this`, we must make sure that
##### Reason ##### Reason
To maintain pointer safety and avoid leaks, we need to consider what pointers a used by a `thread`. To maintain pointer safety and avoid leaks, we need to consider what pointers are used by a `thread`.
If a `thread` joins, we can safely pass pointers to objects in the scope of the `thread` and its enclosing scopes. If a `thread` joins, we can safely pass pointers to objects in the scope of the `thread` and its enclosing scopes.
##### Example ##### Example
@ -11254,7 +11254,7 @@ After that, the usual lifetime and ownership (for local objects) enforcement app
##### Reason ##### Reason
To maintain pointer safety and avoid leaks, we need to consider what pointers a used by a `thread`. To maintain pointer safety and avoid leaks, we need to consider what pointers are used by a `thread`.
If a `thread` is detached, we can safely pass pointers to static and free store objects (only). If a `thread` is detached, we can safely pass pointers to static and free store objects (only).
##### Example ##### Example
@ -11414,7 +11414,7 @@ A `thread` that has not been `detach()`ed when it is destroyed terminates the pr
##### Reason ##### Reason
In general, you cannot know whether a non-`raii_thread` will outlife your thread (so that those pointers will become invalid. In general, you cannot know whether a non-`raii_thread` will outlive the scope of the variables, so that those pointers will become invalid.
##### Example, bad ##### Example, bad
@ -11426,7 +11426,7 @@ In general, you cannot know whether a non-`raii_thread` will outlife your thread
t0.detach(); t0.detach();
} }
The detach` may not be so easy to spot. The `detach` may not be so easy to spot.
Use a `raii_thread` or don't pass the pointer. Use a `raii_thread` or don't pass the pointer.
##### Example, bad ##### Example, bad
@ -11435,10 +11435,10 @@ Use a `raii_thread` or don't pass the pointer.
##### Enforcement ##### Enforcement
Flage pointers to locals passed in the constructor of a plain `thread`. Flag pointers to locals passed in the constructor of a plain `thread`.
### <a name="Rconc-switch"></a>CP.31: Pass small amounts of data between threads by value, reather by reference or pointer ### <a name="Rconc-switch"></a>CP.31: Pass small amounts of data between threads by value, rather by reference or pointer
##### Reason ##### Reason
@ -11447,7 +11447,7 @@ Copying naturally gives unique ownership (simplifies code) and eliminates the po
##### Note ##### Note
Defining "small amount" precisely and is impossible. Defining "small amount" precisely is impossible.
##### Example ##### Example
@ -11462,7 +11462,7 @@ Defining "small amount" precisely and is impossible.
The call of `modify1` involves copying two `string` values; the call of `modify2` does not. The call of `modify1` involves copying two `string` values; the call of `modify2` does not.
On the other hand, the implementation of `modify1` is exactly as we would have written in for single-threaded code, On the other hand, the implementation of `modify1` is exactly as we would have written in for single-threaded code,
wheread the implementation of `modify2` will need some form of locking to avoid data races. whereas the implementation of `modify2` will need some form of locking to avoid data races.
If the string is short (say 10 characters), the call of `modify1` can be surprisingly fast; If the string is short (say 10 characters), the call of `modify1` can be surprisingly fast;
essentially all the cost is in the `thread` switch. If the string is long (say 1,000,000 characters), copying it twice essentially all the cost is in the `thread` switch. If the string is long (say 1,000,000 characters), copying it twice
is probably not a good idea. is probably not a good idea.
@ -11479,7 +11479,7 @@ message passing or shared memory.
##### Reason ##### Reason
If treads are unrelated (that is, not known to be in the same scope or one within the lifetime of the other) If threads are unrelated (that is, not known to be in the same scope or one within the lifetime of the other)
and they need to share free store memory that needs to be deleted, a `shared_ptr` (or equivalent) is the only and they need to share free store memory that needs to be deleted, a `shared_ptr` (or equivalent) is the only
safe way to ensure proper deletion. safe way to ensure proper deletion.
@ -11489,7 +11489,7 @@ safe way to ensure proper deletion.
##### Note ##### Note
* A static object (e.g. a global) can be shard because it is not owned in the sense that some thread is responsible for it's deletion. * A static object (e.g. a global) can be shared because it is not owned in the sense that some thread is responsible for it's deletion.
* An object on free store that is never to be deleted can be shared. * An object on free store that is never to be deleted can be shared.
* An object owned by one thread can be safely shared with another as long as that second thread doesn't outlive the owner. * An object owned by one thread can be safely shared with another as long as that second thread doesn't outlive the owner.
@ -11502,7 +11502,7 @@ safe way to ensure proper deletion.
##### Reason ##### Reason
Context swtiches are expesive. Context swtiches are expensive.
##### Example ##### Example
@ -11561,7 +11561,7 @@ Instead, we could have a set of pre-created worker threads processing the messag
##### Note ##### Note
If you system has a good thread pool, use it. If your system has a good thread pool, use it.
If your system has a good message queue, use it. If your system has a good message queue, use it.
##### Enforcement ##### Enforcement
@ -11636,7 +11636,7 @@ it will immediately go back to sleep, waiting.
##### Enforcement ##### Enforcement
Flag all `waits` without conditions. Flag all `wait`s without conditions.
### <a name="Rconc-time"></a>CP.43: Minimize time spent in a critical section ### <a name="Rconc-time"></a>CP.43: Minimize time spent in a critical section