diff --git a/book/en-us/07-thread.md b/book/en-us/07-thread.md index a2032d1..32df370 100644 --- a/book/en-us/07-thread.md +++ b/book/en-us/07-thread.md @@ -429,7 +429,7 @@ In order to achieve the ultimate performance and achieve consistency of various std::atomic counter = {0}; std::vector vt; for (int i = 0; i < 100; ++i) { - vt.emplace_back([](){ + vt.emplace_back([&](){ counter.fetch_add(1, std::memory_order_relaxed); }); } @@ -444,7 +444,8 @@ In order to achieve the ultimate performance and achieve consistency of various 2. Release/consumption model: In this model, we begin to limit the order of operations between processes. If a thread needs to modify a value, but another thread will have a dependency on that operation of the value, that is, the latter depends. former. Specifically, thread A has completed three writes to `x`, and thread `B` relies only on the third `x` write operation, regardless of the first two write behaviors of `x`, then `A ` When active `x.release()` (ie using `std::memory_order_release`), the option `std::memory_order_consume` ensures that `B` observes `A` when calling `x.load()` Three writes to `x`. Let's look at an example: ```cpp - std::atomic ptr; + // initialize as nullptr to prevent consumer load a dangling pointer + std::atomic ptr(nullptr); int v; std::thread producer([&]() { int* p = new int(42); @@ -500,7 +501,7 @@ In order to achieve the ultimate performance and achieve consistency of various std::atomic counter = {0}; std::vector vt; for (int i = 0; i < 100; ++i) { - vt.emplace_back([](){ + vt.emplace_back([&](){ counter.fetch_add(1, std::memory_order_seq_cst); }); } diff --git a/book/zh-cn/07-thread.md b/book/zh-cn/07-thread.md index b02daa0..73349b0 100644 --- a/book/zh-cn/07-thread.md +++ b/book/zh-cn/07-thread.md @@ -439,7 +439,7 @@ int main() { std::atomic counter = {0}; std::vector vt; for (int i = 0; i < 100; ++i) { - vt.emplace_back([](){ + vt.emplace_back([&](){ counter.fetch_add(1, std::memory_order_relaxed); }); } @@ -453,7 +453,8 @@ int main() { 2. 释放/消费模型:在此模型中,我们开始限制进程间的操作顺序,如果某个线程需要修改某个值,但另一个线程会对该值的某次操作产生依赖,即后者依赖前者。具体而言,线程 A 完成了三次对 `x` 的写操作,线程 `B` 仅依赖其中第三次 `x` 的写操作,与 `x` 的前两次写行为无关,则当 `A` 主动 `x.release()` 时候(即使用 `std::memory_order_release`),选项 `std::memory_order_consume` 能够确保 `B` 在调用 `x.load()` 时候观察到 `A` 中第三次对 `x` 的写操作。我们来看一个例子: ```cpp - std::atomic ptr; + // 初始化为 nullptr 防止 consumer 线程从野指针进行读取 + std::atomic ptr(nullptr); int v; std::thread producer([&]() { int* p = new int(42); @@ -509,7 +510,7 @@ int main() { std::atomic counter = {0}; std::vector vt; for (int i = 0; i < 100; ++i) { - vt.emplace_back([](){ + vt.emplace_back([&](){ counter.fetch_add(1, std::memory_order_seq_cst); }); } diff --git a/code/7/7.8.memory.order.cpp b/code/7/7.8.memory.order.cpp index b7096f3..e8b1cc7 100644 --- a/code/7/7.8.memory.order.cpp +++ b/code/7/7.8.memory.order.cpp @@ -15,15 +15,15 @@ using namespace std; using namespace std::chrono; -atomic counter = {0}; const int N = 10000; void relaxed_order() { cout << "relaxed_order: " << endl; + atomic counter = {0}; vector vt; for (int i = 0; i < N; ++i) { - vt.emplace_back([](){ + vt.emplace_back([&](){ counter.fetch_add(1, memory_order_relaxed); }); } @@ -86,9 +86,10 @@ void release_acquire_order() { void sequential_consistent_order() { cout << "sequential_consistent_order: " << endl; + atomic counter = {0}; vector vt; for (int i = 0; i < N; ++i) { - vt.emplace_back([](){ + vt.emplace_back([&](){ counter.fetch_add(1, memory_order_seq_cst); }); }