Merge branch 'thread-tooling' of https://github.com/tituswinters/CppCoreGuidelines into tituswinters-thread-tooling

This commit is contained in:
Andrew Pardoe 2017-02-06 11:36:22 -08:00
commit 20403c8d6d
2 changed files with 46 additions and 18 deletions

View File

@ -7365,9 +7365,9 @@ But heed the warning: [Avoid "naked" `union`s](#Ru-naked)
##### Example ##### Example
// Short string optimization // Short string optimization
constexpr size_t buffer_size = 16; // Slightly larger than the size of a pointer constexpr size_t buffer_size = 16; // Slightly larger than the size of a pointer
class Immutable_string { class Immutable_string {
public: public:
Immutable_string(const char* str) : Immutable_string(const char* str) :
@ -7380,18 +7380,18 @@ But heed the warning: [Avoid "naked" `union`s](#Ru-naked)
strcpy_s(string_ptr, size + 1, str); strcpy_s(string_ptr, size + 1, str);
} }
} }
~Immutable_string() ~Immutable_string()
{ {
if (size >= buffer_size) if (size >= buffer_size)
delete string_ptr; delete string_ptr;
} }
const char* get_str() const const char* get_str() const
{ {
return (size < buffer_size) ? string_buffer : string_ptr; return (size < buffer_size) ? string_buffer : string_ptr;
} }
private: private:
// If the string is short enough, we store the string itself // If the string is short enough, we store the string itself
// instead of a pointer to the string. // instead of a pointer to the string.
@ -7399,7 +7399,7 @@ But heed the warning: [Avoid "naked" `union`s](#Ru-naked)
char* string_ptr; char* string_ptr;
char string_buffer[buffer_size]; char string_buffer[buffer_size];
}; };
const size_t size; const size_t size;
}; };
@ -11697,16 +11697,40 @@ this can be a security risk.
##### Enforcement ##### Enforcement
Some is possible, do at least something. When possible, rely on tooling enforcement, but be aware that any tooling
There are commercial and open-source tools that try to address this problem, but static tools often have many false positives and run-time tools often have a significant cost. solution has costs and blind spots. Defense in depth (multiple tools, multiple
We hope for better tools. approaches) is particularly valuable here.
Help the tools: In the realm of static enforcement,
both [clang](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html) and some
older versions of [GCC](https://gcc.gnu.org/wiki/ThreadSafetyAnnotation) have
some support for static annotation of thread safety properties. Consistent use
of this technique turns many classes of thread-safety errors into compile-time
errors. The annotations are generally local (marking a particular member
variable as guarded by a particular mutex), and are usually easy to
learn. However, as with many static tools, it can often present false
negatives - cases that should have been caught but were allowed.
* less global data Clang's [Thread Sanitizer](http://clang.llvm.org/docs/ThreadSanitizer.html) (aka
* fewer `static` variables TSAN) is a powerful example of dynamic tools: it changes the build and execution
* more use of stack memory (and don't pass pointers around too much) of your program to add bookkeeping on memory access, absolutely identifying data
* more immutable data (literals, `constexpr`, and `const`) races in a given execution of your binary. The cost for this is both memory
(5-10x in most cases) and CPU slowdown (2-20x). Dynamic tools like this are best
when applied to integration tests, canary pushes, or unittests that operate on
multiple threads. Workload matters: When TSAN identifies a problem, it is
effectively always an actual data race, but it can only identify races seen in a
given execution.
There are many other tools, both commercial and open-source. Thread safety is
challenging, often getting the better of experienced programmers: tooling is an
important strategy to mitigate those risks.
There are other ways you can mitigate the chance of data races:
* Avoid global data
* Avoid `static` variables
* More use of value types on the stack (and don't pass pointers around too much)
* More use of immutable data (literals, `constexpr`, and `const`)
### <a name="Rconc-data"></a>CP.3: Minimize explicit sharing of writable data ### <a name="Rconc-data"></a>CP.3: Minimize explicit sharing of writable data
@ -12709,7 +12733,7 @@ Example with thread-safe static local variables of C++11.
static My_class my_object; // Constructor called only once static My_class my_object; // Constructor called only once
// ... // ...
} }
class My_class class My_class
{ {
public: public:
@ -12732,7 +12756,7 @@ Double-checked locking is easy to mess up. If you really need to write your own
##### Example, bad ##### Example, bad
Even if the following example works correctly on most hardware platforms, it is not guaranteed to work by the C++ standard. The x_init.load(memory_order_relaxed) call may see a value from outside of the lock guard. Even if the following example works correctly on most hardware platforms, it is not guaranteed to work by the C++ standard. The x_init.load(memory_order_relaxed) call may see a value from outside of the lock guard.
atomic<bool> x_init; atomic<bool> x_init;
@ -12749,12 +12773,12 @@ Even if the following example works correctly on most hardware platforms, it is
One of the conventional patterns is below. One of the conventional patterns is below.
std::atomic<int> state; std::atomic<int> state;
// If state == SOME_ACTION_NEEDED maybe an action is needed, maybe not, we need to // If state == SOME_ACTION_NEEDED maybe an action is needed, maybe not, we need to
// check again in a lock. However, if state != SOME_ACTION_NEEDED, then we can be // check again in a lock. However, if state != SOME_ACTION_NEEDED, then we can be
// sure that an action is not needed. This is the basic assumption of double-checked // sure that an action is not needed. This is the basic assumption of double-checked
// locking. // locking.
if (state == SOME_ACTION_NEEDED) if (state == SOME_ACTION_NEEDED)
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);

View File

@ -1,7 +1,9 @@
' '
0xFF0000 0xFF0000
0b0101'0101 0b0101'0101
10x
'14 '14
20x
2D 2D
2K 2K
2ndEdition 2ndEdition
@ -69,6 +71,7 @@ CComPtr
cerr cerr
chrono chrono
cin cin
Clang's
class' class'
clib clib
Cline99 Cline99
@ -492,6 +495,7 @@ toolchains
TotallyOrdered TotallyOrdered
TP TP
tradeoff tradeoff
TSAN
TSs TSs
tt tt
typeid typeid