当前位置: 首页 > news >正文

为什么有些公司却没有自己的网站新的龙岗网站建设

为什么有些公司却没有自己的网站,新的龙岗网站建设,信息平台网站的建设 文档,建设工程管理专业学什么以下是经过优化排版后的5.3节内容#xff0c;详细解释了C中的同步操作和强制排序机制。每个部分都有详细的注释和结构化展示。 文章目录 5.3 同步操作和强制排序假设场景示例代码 5.3.1 同步发生 (Synchronizes-with)基本思想 5.3.2 先行发生 (Happens-before)单线程环境多线程…以下是经过优化排版后的5.3节内容详细解释了C中的同步操作和强制排序机制。每个部分都有详细的注释和结构化展示。 文章目录 5.3 同步操作和强制排序假设场景示例代码 5.3.1 同步发生 (Synchronizes-with)基本思想 5.3.2 先行发生 (Happens-before)单线程环境多线程环境 5.3.3 内存顺序 (Memory Order)总结5.3.3 原子操作的内存序顺序一致性 (Sequentially Consistent)示例代码性能影响 自由序 (Relaxed Ordering)示例代码 获取-释放序 (Acquire-Release Ordering)示例代码性能优势 非限制操作示例示例代码结果分析 总结5.3.3 原子操作的内存序获取-释放序操作会影响释放操作示例代码结果分析 获取-释放序传递同步示例代码结果分析 合并同步变量示例代码 memory_order_consume 数据相关性示例代码结果分析 总结5.3.4 释放队列与同步示例代码使用原子操作从队列中读取数据结果分析 5.3.5 栅栏Fences示例代码栅栏可以让自由操作变得有序结果分析 5.3.6 原子操作对非原子操作的排序示例代码使用非原子操作执行序列结果分析 5.3.7 非原子操作排序示例代码非原子操作排序结果分析 同步工具总结std::threadstd::mutex, std::timed_mutex, std::recursive_mutex, std::recursibe_timed_mutexstd::shared_mutex, std::shared_timed_mutexstd::promise, std::future, std::shared_futurestd::async, std::future, std::shared_futurestd::experimental::latch, std::experimental::barrier, std::experimental::flex_barrierstd::condition_variable, std::condition_variable_any 5.3 同步操作和强制排序 在多线程环境中确保数据的一致性和正确性至关重要。通过使用原子操作和适当的内存顺序可以实现线程间的同步和强制排序。 假设场景 假设我们有两个线程一个用于写入数据writer_thread另一个用于读取数据reader_thread。为了避免竞争条件写入线程需要设置一个标志来表明数据已经准备好以便读取线程可以在标志设置后安全地访问数据。 示例代码 #include vector #include atomic #include iostream #include thread #include chronostd::vectorint data; std::atomicbool data_ready(false);void reader_thread() {while (!data_ready.load()) { // 1: 等待数据准备就绪std::this_thread::sleep_for(std::chrono::milliseconds(1));}std::cout The answer data[0] \n; // 2: 读取数据 }void writer_thread() {data.push_back(42); // 3: 写入数据data_ready.store(true); // 4: 标记数据已准备就绪 }在这个例子中 等待循环 (while (!data_ready.load())) 确保读取线程不会在数据未准备好时访问数据。读取操作 (data[0]) 在 data_ready 标志被设置为 true 后进行。写入操作 (data.push_back(42)) 和 标记操作 (data_ready.store(true)) 确保数据在读取前已经准备好。 尽管每一个数据项都是原子的但非原子读写操作可能破坏访问顺序导致未定义行为。为了确保正确的顺序我们需要理解“先行”和“同步发生”的概念。 5.3.1 同步发生 (Synchronizes-with) “同步发生”是指两个原子操作之间的关系其中一个操作必须先于另一个操作完成。这种关系仅存在于原子类型之间。 基本思想 原子写操作 W 对变量 x 进行标记并与对 x 的原子读操作同步。读操作要么读到 W 操作写入的内容要么读到 W 之后同一线程上的原子写操作写入的值亦或是任意线程对 x 的一系列原子读-改-写操作如 fetch_add() 或 compare_exchange_weak()。 例如 std::atomicint x(0); std::atomicbool flag(false);// 线程 A x.store(42, std::memory_order_relaxed); flag.store(true, std::memory_order_release);// 线程 B while (!flag.load(std::memory_order_acquire)) {std::this_thread::yield(); } int value x.load(std::memory_order_relaxed);在这个例子中 线程 A 中的 x.store(42) 和 flag.store(true) 是原子写操作。线程 B 中的 flag.load() 和 x.load() 是原子读操作。当 flag 被设置为 true 时线程 A 的写操作与线程 B 的读操作同步发生。 5.3.2 先行发生 (Happens-before) “先行发生”是指程序中操作顺序的基本构建块。它规定了某个操作如何影响另一个操作。 单线程环境 在一个单线程环境中如果操作 A 发生在操作 B 之前那么 A 就先行于 B。例如 int get_num() {static int i 0;return i; }void foo(int a, int b) {std::cout a , b std::endl; }int main() {foo(get_num(), get_num()); // 无序调用 get_num() }在这个例子中get_num() 的调用顺序未指定输出可能是“1,2”或“2,1”。 多线程环境 在多线程环境中“先行发生”关系依赖于同步关系 如果操作 A 在一个线程上并且该线程先行于另一个线程上的操作 B那么 A 就先行于 B。如果操作 A 与另一个线程上的操作 B 同步那么 A 就线程间先行于 B。 传递关系如果 A 先行于 B并且 B 先行于 C那么 A 就先行于 C。 示例代码 std::atomicbool ready(false);void thread_a() {data.push_back(42); // 写入数据ready.store(true, std::memory_order_release); // 设置标志 }void thread_b() {while (!ready.load(std::memory_order_acquire)) { // 等待标志std::this_thread::yield();}std::cout The answer data[0] \n; // 读取数据 }在这个例子中 thread_a 中的写操作先行于 ready.store(true)。ready.load() 先行于 thread_b 中的读操作。因此写操作先行于读操作。 5.3.3 内存顺序 (Memory Order) 内存顺序决定了原子操作的行为以及它们与其他操作的关系。常见的内存顺序包括 memory_order_relaxed: 不保证任何顺序。memory_order_consume: 依赖于当前线程的操作结果。memory_order_acquire: 确保后续操作不会被重排序到当前操作之前。memory_order_release: 确保之前的操作不会被重排序到当前操作之后。memory_order_acq_rel: 结合 acquire 和 release 语义。memory_order_seq_cst: 提供全局顺序一致性。 示例代码 std::atomicint x(0); std::atomicint y(0);// 线程 A x.store(1, std::memory_order_relaxed); y.store(1, std::memory_order_release);// 线程 B while (y.load(std::memory_order_acquire) 0) {std::this_thread::yield(); } int value x.load(std::memory_order_relaxed);在这个例子中 y.store(1, std::memory_order_release) 确保之前的 x.store(1) 不会被重排序到其后。y.load(std::memory_order_acquire) 确保后续的 x.load() 不会读取到旧值。 总结 通过理解和应用“同步发生”和“先行发生”关系我们可以确保多线程程序中的数据一致性和正确性。合理选择内存顺序也是至关重要的它可以帮助我们控制操作的顺序并避免潜在的竞争条件。 这些规则是编写高效、安全的多线程程序的基础能够帮助我们在复杂的并发环境中管理数据共享和同步。希望这些解释和示例能帮助你更好地理解和应用这些概念。 以下是经过优化排版后的5.3.3节内容详细解释了C中的原子操作内存序。每个部分都有详细的注释和结构化展示。 5.3.3 原子操作的内存序 在多线程编程中内存序Memory Order决定了原子操作的行为及其与其他操作的关系。C提供了六种不同的内存序选项 memory_order_relaxedmemory_order_consumememory_order_acquirememory_order_releasememory_order_acq_relmemory_order_seq_cst 除非为特定的操作指定一个序列选项默认内存序是 memory_order_seq_cst顺序一致性。尽管有六个选项但它们代表三种主要的内存模型顺序一致性、获取-释放序和自由序。 顺序一致性 (Sequentially Consistent) 默认内存序 memory_order_seq_cst 是最简单且最容易理解的内存序。它确保所有线程看到的操作顺序是一致的。 示例代码 #include atomic #include thread #include cassertstd::atomicbool x(false), y(false); std::atomicint z(0);void write_x() {x.store(true, std::memory_order_seq_cst); // 1: 写入x }void write_y() {y.store(true, std::memory_order_seq_cst); // 2: 写入y }void read_x_then_y() {while (!x.load(std::memory_order_seq_cst)); // 等待x变为trueif (y.load(std::memory_order_seq_cst)) { // 3: 检查y是否为truez;} }void read_y_then_x() {while (!y.load(std::memory_order_seq_cst)); // 等待y变为trueif (x.load(std::memory_order_seq_cst)) { // 4: 检查x是否为truez;} }int main() {x false;y false;z 0;std::thread a(write_x);std::thread b(write_y);std::thread c(read_x_then_y);std::thread d(read_y_then_x);a.join();b.join();c.join();d.join();assert(z.load() ! 0); // 断言z不为0 }在这个例子中 write_x 和 write_y 分别设置 x 和 y 为 true。read_x_then_y 和 read_y_then_x 分别等待 x 和 y 变为 true然后检查另一个变量并增加 z 的值。 由于使用了 memory_order_seq_cst所有的操作都保持全局一致的顺序因此断言不会触发。 性能影响 虽然顺序一致性是最直观的内存序但在多核系统上会带来较大的性能开销因为它需要在多个处理器之间进行同步操作。 自由序 (Relaxed Ordering) memory_order_relaxed 提供最小的同步保证适用于不需要严格顺序的应用场景。 示例代码 #include atomic #include thread #include cassertstd::atomicbool x(false), y(false); std::atomicint z(0);void write_x_then_y() {x.store(true, std::memory_order_relaxed); // 1: 写入xy.store(true, std::memory_order_relaxed); // 2: 写入y }void read_y_then_x() {while (!y.load(std::memory_order_relaxed)); // 3: 等待y变为trueif (x.load(std::memory_order_relaxed)) { // 4: 检查x是否为truez;} }int main() {x false;y false;z 0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load() ! 0); // 断言可能会触发 }在这个例子中 write_x_then_y 先写入 x然后写入 y但没有顺序保证。read_y_then_x 等待 y 变为 true然后检查 x 是否为 true 并增加 z 的值。 由于使用了 memory_order_relaxed读取操作可能看不到最新的写入值因此断言可能会触发。 获取-释放序 (Acquire-Release Ordering) 获取-释放序提供了比自由序更强的同步保证但不像顺序一致性那样严格。 示例代码 #include atomic #include thread #include cassertstd::atomicbool x(false), y(false); std::atomicint z(0);void write_x() {x.store(true, std::memory_order_release); // 1: 写入x }void write_y() {y.store(true, std::memory_order_release); // 2: 写入y }void read_x_then_y() {while (!x.load(std::memory_order_acquire)); // 等待x变为trueif (y.load(std::memory_order_acquire)) { // 3: 检查y是否为truez;} }void read_y_then_x() {while (!y.load(std::memory_order_acquire)); // 等待y变为trueif (x.load(std::memory_order_acquire)) { // 4: 检查x是否为truez;} }int main() {x false;y false;z 0;std::thread a(write_x);std::thread b(write_y);std::thread c(read_x_then_y);std::thread d(read_y_then_x);a.join();b.join();c.join();d.join();assert(z.load() ! 0); // 断言可能会触发 }在这个例子中 write_x 和 write_y 使用 memory_order_release 标记写入操作。read_x_then_y 和 read_y_then_x 使用 memory_order_acquire 进行读取操作。 获取-释放序确保了一个线程的释放操作与另一个线程的获取操作同步从而提供了一定程度的顺序保证但仍不如顺序一致性那么严格。 性能优势 获取-释放序通常比顺序一致性更高效因为它只需要在相关线程之间进行同步而不是全局同步。 非限制操作示例 为了更好地理解非限制操作考虑以下多线程示例 示例代码 #include thread #include atomic #include iostreamstd::atomicint x(0), y(0), z(0); // 1: 全局原子变量 std::atomicbool go(false); // 2: 同步信号unsigned const loop_count 10;struct read_values {int x, y, z; };read_values values1[loop_count], values2[loop_count], values3[loop_count], values4[loop_count], values5[loop_count];void increment(std::atomicint* var_to_inc, read_values* values) {while (!go) std::this_thread::yield(); // 3: 等待信号for (unsigned i 0; i loop_count; i) {values[i].x x.load(std::memory_order_relaxed);values[i].y y.load(std::memory_order_relaxed);values[i].z z.load(std::memory_order_relaxed);var_to_inc-store(i 1, std::memory_order_relaxed); // 4: 更新变量std::this_thread::yield();} }void read_vals(read_values* values) {while (!go) std::this_thread::yield(); // 5: 等待信号for (unsigned i 0; i loop_count; i) {values[i].x x.load(std::memory_order_relaxed);values[i].y y.load(std::memory_order_relaxed);values[i].z z.load(std::memory_order_relaxed);std::this_thread::yield();} }void print(read_values* v) {for (unsigned i 0; i loop_count; i) {if (i) std::cout ,;std::cout ( v[i].x , v[i].y , v[i].z );}std::cout std::endl; }int main() {x 0;y 0;z 0;go false;std::thread t1(increment, x, values1);std::thread t2(increment, y, values2);std::thread t3(increment, z, values3);std::thread t4(read_vals, values4);std::thread t5(read_vals, values5);go true; // 6: 开始执行主循环的信号t5.join();t4.join();t3.join();t2.join();t1.join();print(values1); // 7: 打印最终结果print(values2);print(values3);print(values4);print(values5); }在这个例子中 三个全局原子变量 x, y, z 和一个同步信号 go。每个线程循环10次使用 memory_order_relaxed 读取三个原子变量的值并存储在一个数组中。三个线程每次通过循环更新其中一个原子变量剩下的两个线程负责读取。 输出示例 (0,0,0),(1,0,0),(2,0,0),(3,0,0),(4,0,0),(5,7,0),(6,7,8),(7,9,8),(8,9,8),(9,9,10) (0,0,0),(0,1,0),(0,2,0),(1,3,5),(8,4,5),(8,5,5),(8,6,6),(8,7,9),(10,8,9),(10,9,10) (0,0,0),(0,0,1),(0,0,2),(0,0,3),(0,0,4),(0,0,5),(0,0,6),(0,0,7),(0,0,8),(0,0,9) (1,3,0),(2,3,0),(2,4,1),(3,6,4),(3,9,5),(5,10,6),(5,10,8),(5,10,10),(9,10,10),(10,10,10) (0,0,0),(0,0,0),(0,0,0),(6,3,7),(6,5,7),(7,7,7),(7,8,7),(8,8,7),(8,8,9),(8,8,9)结果分析 第一组值中 x 增加1第二组值中 y 增加1第三组中 z 增加1。x 元素只在给定集中增加y 和 z 也一样但不是均匀增加并且每个线程中的相对顺序不同。线程3看不到 x 或 y 的任何更新但它能看到 z 的更新。 总结 通过理解和应用不同的内存序选项可以在多线程编程中实现高效的同步和强制排序。每种内存序都有其适用场景 顺序一致性 (memory_order_seq_cst)最简单且直观但性能开销较大。自由序 (memory_order_relaxed)性能最佳但缺乏严格的顺序保证。获取-释放序 (memory_order_acquire 和 memory_order_release)提供了较强的同步保证同时保持较高的性能。 选择合适的内存序可以帮助你在保证程序正确性的同时最大化性能。希望这些解释和示例能帮助你更好地理解和应用这些概念。 以下是经过优化排版后的5.3.3节内容详细解释了C中的原子操作内存序特别是获取-释放序的操作及其传递同步特性。每个部分都有详细的注释和结构化展示。 5.3.3 原子操作的内存序 在多线程编程中内存序Memory Order决定了原子操作的行为及其与其他操作的关系。C提供了六种不同的内存序选项 memory_order_relaxedmemory_order_consumememory_order_acquirememory_order_releasememory_order_acq_relmemory_order_seq_cst 除非为特定的操作指定一个序列选项默认内存序是 memory_order_seq_cst顺序一致性。尽管有六个选项但它们代表三种主要的内存模型顺序一致性、获取-释放序和自由序。 获取-释放序操作会影响释放操作 示例代码 #include atomic #include thread #include cassertstd::atomicbool x(false), y(false); std::atomicint z(0);void write_x_then_y() {x.store(true, std::memory_order_relaxed); // 1: 写入xy.store(true, std::memory_order_release); // 2: 写入y }void read_y_then_x() {while (!y.load(std::memory_order_acquire)); // 3: 等待y变为trueif (x.load(std::memory_order_relaxed)) { // 4: 检查x是否为truez;} }int main() {x false;y false;z 0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load() ! 0); // 断言不会触发 }在这个例子中 write_x_then_y 先写入 x然后写入 y。read_y_then_x 等待 y 变为 true然后检查 x 是否为 true 并增加 z 的值。 由于使用了 memory_order_release 和 memory_order_acquire读取操作会看到最新的写入值因此断言不会触发。 结果分析 存储 x 使用的是 memory_order_relaxed没有顺序保证。存储 y 使用的是 memory_order_release确保后续的加载操作能看到这个值。加载 y 使用的是 memory_order_acquire确保能看到之前的所有释放操作。 因此存储 x 的操作先行于存储 y 的操作并且扩展到对 x 的读取操作使得 z 最终不为零。 获取-释放序传递同步 为了考虑传递顺序至少需要三个线程。第一个线程用来修改共享变量第二个线程使用“加载-获取”读取由“存储-释放”操作过的变量并且再对第二个变量进行“存储-释放”操作。最后由第三个线程通过“加载-获取”读取第二个共享变量并提供“加载-获取”操作来读取被“存储-释放”操作写入的值。 示例代码 #include atomic #include thread #include cassertstd::atomicint data[5]; std::atomicbool sync1(false), sync2(false);void thread_1() {data[0].store(42, std::memory_order_relaxed);data[1].store(97, std::memory_order_relaxed);data[2].store(17, std::memory_order_relaxed);data[3].store(-141, std::memory_order_relaxed);data[4].store(2003, std::memory_order_relaxed);sync1.store(true, std::memory_order_release); // 1. 设置sync1 }void thread_2() {while (!sync1.load(std::memory_order_acquire)); // 2. 直到sync1设置后循环结束sync2.store(true, std::memory_order_release); // 3. 设置sync2 }void thread_3() {while (!sync2.load(std::memory_order_acquire)); // 4. 直到sync2设置后循环结束assert(data[0].load(std::memory_order_relaxed) 42);assert(data[1].load(std::memory_order_relaxed) 97);assert(data[2].load(std::memory_order_relaxed) 17);assert(data[3].load(std::memory_order_relaxed) -141);assert(data[4].load(std::memory_order_relaxed) 2003); }int main() {std::thread t1(thread_1);std::thread t2(thread_2);std::thread t3(thread_3);t1.join();t2.join();t3.join(); }在这个例子中 thread_1 将数据存储到 data 中并设置 sync1。thread_2 等待 sync1 被设置后设置 sync2。thread_3 等待 sync2 被设置后读取 data 中的数据并进行断言。 由于 thread_2 只接触到 sync1 和 sync2对于 thread_1 和 thread_3 的同步就足够了这能保证断言不会触发。 结果分析 thread_1 将数据存储到 data 中先行于存储 sync1。对 sync1 的加载最终会看到 thread_1 存储的值。thread_3 的加载操作位于存储 sync2 操作的前面。存储 sync2 因此先行于 thread_3 的加载从而保证断言都不会触发。 合并同步变量 可以将 sync1 和 sync2 通过在 thread_2 中使用“读-改-写”操作 (memory_order_acq_rel) 合并成一个独立的变量。其中会使用 compare_exchange_strong() 来保证 thread_1 对变量只进行一次更新。 示例代码 #include atomic #include thread #include cassertstd::atomicint data[5]; std::atomicint sync(0);void thread_1() {data[0].store(42, std::memory_order_relaxed);data[1].store(97, std::memory_order_relaxed);data[2].store(17, std::memory_order_relaxed);data[3].store(-141, std::memory_order_relaxed);data[4].store(2003, std::memory_order_relaxed);sync.store(1, std::memory_order_release); }void thread_2() {int expected 1;while (!sync.compare_exchange_strong(expected, 2,std::memory_order_acq_rel))expected 1; }void thread_3() {while (sync.load(std::memory_order_acquire) 2);assert(data[0].load(std::memory_order_relaxed) 42);assert(data[1].load(std::memory_order_relaxed) 97);assert(data[2].load(std::memory_order_relaxed) 17);assert(data[3].load(std::memory_order_relaxed) -141);assert(data[4].load(std::memory_order_relaxed) 2003); }int main() {std::thread t1(thread_1);std::thread t2(thread_2);std::thread t3(thread_3);t1.join();t2.join();t3.join(); }在这个例子中 thread_1 将数据存储到 data 中并设置 sync 为 1。thread_2 使用 compare_exchange_strong 将 sync 从 1 更新为 2。thread_3 等待 sync 大于等于 2 后读取 data 中的数据并进行断言。 使用 memory_order_acq_rel 的“读-改-写”操作选择语义非常重要。例子中想要同时进行获取和释放的语义所以 memory_order_acq_rel 是一个不错的选择。 memory_order_consume 数据相关性 memory_order_consume 是一种特殊的内存序完全依赖于数据并展示了与线程间先行关系的不同之处。尽管它在C17中不推荐使用但仍有必要了解其概念。 示例代码 #include atomic #include thread #include cassert #include stringstruct X {int i;std::string s; };std::atomicX* p; std::atomicint a;void create_x() {X* x new X;x-i 42;x-s hello;a.store(99, std::memory_order_relaxed); // 1p.store(x, std::memory_order_release); // 2 }void use_x() {X* x;while (!(x p.load(std::memory_order_consume))) // 3std::this_thread::sleep_for(std::chrono::microseconds(1));assert(x-i 42); // 4assert(x-s hello); // 5assert(a.load(std::memory_order_relaxed) 99); // 6 }int main() {std::thread t1(create_x);std::thread t2(use_x);t1.join();t2.join(); }在这个例子中 create_x 创建一个 X 结构体实例并将其指针存储在 p 中。use_x 等待 p 被设置为非空值然后访问 X 结构体的成员。 由于 memory_order_consume 的使用X 结构体中的数据成员所在的断言语句不会被触发。然而加载 a 的断言不能确定是否触发因为这个操作标记为 memory_order_relaxed并不依赖于 p 的加载操作。 结果分析 存储 a 在存储 p 之前并且存储 p 的操作标记为 memory_order_release。加载 p 的操作标记为 memory_order_consume因此存储 p 仅先行那些需要加载 p 的操作。对 x 变量操作的表达式对加载 p 的操作携带有依赖所以 X 结构体中数据成员所在的断言语句不会被触发。 总结 通过理解和应用不同的内存序选项可以在多线程编程中实现高效的同步和强制排序。每种内存序都有其适用场景 顺序一致性 (memory_order_seq_cst)最简单且直观但性能开销较大。自由序 (memory_order_relaxed)性能最佳但缺乏严格的顺序保证。获取-释放序 (memory_order_acquire 和 memory_order_release)提供了较强的同步保证同时保持较高的性能。memory_order_consume依赖于数据的相关性但在实际应用中不推荐使用。 选择合适的内存序可以帮助你在保证程序正确性的同时最大化性能。希望这些解释和示例能帮助你更好地理解和应用这些概念。 以下是经过优化排版后的5.3.4至5.3.7节内容详细解释了C中的释放队列、栅栏操作及其对非原子操作的排序。每个部分都有详细的注释和结构化展示。 5.3.4 释放队列与同步 在多线程编程中释放队列Release Sequence是确保不同线程之间正确同步的重要机制。通过使用适当的内存序标记可以保证存储和加载操作之间的同步关系。 示例代码使用原子操作从队列中读取数据 #include atomic #include thread #include vectorstd::vectorint queue_data; std::atomicint count;void populate_queue() {unsigned const number_of_items 20;queue_data.clear();for (unsigned i 0; i number_of_items; i) {queue_data.push_back(i);}count.store(number_of_items, std::memory_order_release); // 1 初始化存储 }void consume_queue_items() {while (true) {int item_index;if ((item_index count.fetch_sub(1, std::memory_order_acquire)) 0) { // 2 “读-改-写”操作wait_for_more_items(); // 3 等待更多元素continue;}process(queue_data[item_index - 1]); // 4 安全读取queue_data} }int main() {std::thread a(populate_queue);std::thread b(consume_queue_items);std::thread c(consume_queue_items);a.join();b.join();c.join(); }结果分析 populate_queue 函数初始化共享队列并设置计数器。consume_queue_items 函数从队列中获取元素并处理它们。使用 memory_order_release 和 memory_order_acquire 确保存储和加载操作之间的同步。 当只有一个消费者线程时一切正常。如果有两个消费者线程第二个线程会看到第一个线程修改的值从而避免条件竞争。 5.3.5 栅栏Fences 栅栏操作是对内存序列进行约束的全局操作限制编译器或硬件对指令的重新排序。栅栏操作可以确保特定的操作顺序。 示例代码栅栏可以让自由操作变得有序 #include atomic #include thread #include assert.hstd::atomicbool x(false), y(false); std::atomicint z(0);void write_x_then_y() {x.store(true, std::memory_order_relaxed); // 1std::atomic_thread_fence(std::memory_order_release); // 2y.store(true, std::memory_order_relaxed); // 3 }void read_y_then_x() {while (!y.load(std::memory_order_relaxed)); // 4std::atomic_thread_fence(std::memory_order_acquire); // 5if (x.load(std::memory_order_relaxed)) // 6z; }int main() {x false;y false;z 0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load() ! 0); // 7 }结果分析 write_x_then_y 函数使用释放栅栏确保 x 和 y 的存储顺序。read_y_then_x 函数使用获取栅栏确保 y 和 x 的加载顺序。栅栏操作确保了存储和加载操作之间的同步关系避免了条件竞争。 如果将存储和加载操作标记为 memory_order_relaxed则需要栅栏来强制执行顺序。 5.3.6 原子操作对非原子操作的排序 即使使用非原子变量也可以通过栅栏操作确保操作的顺序性。 示例代码使用非原子操作执行序列 #include atomic #include thread #include assert.hbool x false; // x现在是一个非原子变量 std::atomicbool y(false); std::atomicint z(0);void write_x_then_y() {x true; // 1 在栅栏前存储xstd::atomic_thread_fence(std::memory_order_release);y.store(true, std::memory_order_relaxed); // 2 在栅栏后存储y }void read_y_then_x() {while (!y.load(std::memory_order_relaxed)); // 3 在#2写入前持续等待std::atomic_thread_fence(std::memory_order_acquire);if (x) // 4 这里读取到的值是#1中写入z; }int main() {x false;y false;z 0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load() ! 0); // 5 断言将不会触发 }结果分析 write_x_then_y 函数使用释放栅栏确保 x 和 y 的存储顺序。read_y_then_x 函数使用获取栅栏确保 y 和 x 的加载顺序。尽管 x 是一个非原子变量但栅栏操作仍然确保了操作的顺序性。 5.3.7 非原子操作排序 通过使用栅栏操作可以对非原子操作进行排序确保其顺序性和同步性。 示例代码非原子操作排序 #include atomic #include thread #include cassertbool x false; // 非原子变量 std::atomicbool y(false); std::atomicint z(0);void write_x_then_y() {x true; // 1 在栅栏前存储xstd::atomic_thread_fence(std::memory_order_release);y.store(true, std::memory_order_relaxed); // 2 在栅栏后存储y }void read_y_then_x() {while (!y.load(std::memory_order_relaxed)); // 3 在#2写入前持续等待std::atomic_thread_fence(std::memory_order_acquire);if (x) // 4 这里读取到的值是#1中写入z; }int main() {x false;y false;z 0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load() ! 0); // 5 断言将不会触发 }结果分析 write_x_then_y 函数使用释放栅栏确保 x 和 y 的存储顺序。read_y_then_x 函数使用获取栅栏确保 y 和 x 的加载顺序。即使 x 是一个非原子变量栅栏操作仍然确保了操作的顺序性和同步性。 同步工具总结 以下是一些常用的同步工具及其作用 std::thread 构造函数与调用函数或新线程的可调用对象间的同步。对 std::thread 对象调用 join 可以和对应的线程进行同步。 std::mutex, std::timed_mutex, std::recursive_mutex, std::recursibe_timed_mutex 对给定互斥量对象调用 lock 和 unlock以及对 try_lock、try_lock_for 或 try_lock_until会形成该互斥量的锁序。对给定的互斥量调用 unlock需要在调用 lock 或成功调用 try_lock、try_lock_for 或 try_lock_until 之后这样才符合互斥量的锁序。 std::shared_mutex, std::shared_timed_mutex 对给定互斥量对象调用 lock、unlock、lock_shared 和 unlock_shared以及对 try_lock、try_lock_for、try_lock_until、try_lock_shared、try_lock_shared_for 或 try_lock_shared_until 的成功调用会形成该互斥量的锁序。 std::promise, std::future, std::shared_future 成功调用 std::promise 对象的 set_value 或 set_exception 与成功的调用 wait 或 get 之间同步。成功调用 std::packaged_task 对象的函数操作符与成功的调用 wait 或 get 之间同步。 std::async, std::future, std::shared_future 使用 std::launch::async 策略性的通过 std::async 启动线程执行任务与成功的调用 wait 和 get 之间是同步的。使用 std::launch::deferred 策略性的通过 std::async 启动任务与成功的调用 wait 和 get 之间是同步的。 std::experimental::latch, std::experimental::barrier, std::experimental::flex_barrier 对 std::experimental::latch 实例调用 count_down 或 count_down_and_wait 与在该对象上成功的调用 wait 或 count_down_and_wait 之间是同步的。对 std::experimental::barrier 实例调用 arrive_and_wait 或 arrive_and_drop 与在该对象上随后成功完成的 arrive_and_wait 之间是同步的。 std::condition_variable, std::condition_variable_any 条件变量不提供任何同步关系所有同步都由互斥量提供。 这些同步工具提供了丰富的功能帮助开发者在多线程环境中实现正确的同步和顺序控制。希望这些解释和示例能帮助你更好地理解和应用这些概念。
http://www.hkea.cn/news/14280322/

相关文章:

  • 商城网站 价格深圳 网站建设培训学校
  • 江苏大丰做网站软件开发工具的基本功能
  • 网站建设前期应该做哪些准备东莞网站程序
  • 酷站欣赏网络营销策划方案简介
  • 网站开发可以用gif吗好康的网站代码
  • 我的专业网站建设策划书上海传媒公司官网
  • 淄博专业网站建设公司海外直播
  • 企业手机网站模板下载做的比较好的网站有哪些
  • 网站建设汽车后市场分析销售怎么找客户
  • 做装修的推广网站有那种网页设计案例
  • 海南响应式网站建设方案摄影展示网站源码
  • 云教育科技网站建设为企业策划一次网络营销活动
  • 做网站如何放入图像hcms wordpress
  • 常见网站建设网站单个页面做301
  • 西宁市规划和建设局网站wordpress插件开发
  • 电脑网站做名片wordpress分类模版设置插件
  • 如何制作微信网站自己制作网站的方法是
  • 如何跟进psd做网站下载爱南宁乘车
  • 建设微信网站需要服务器营销师
  • 个人网站模块网站免费推广大全
  • 福州微信营销网站建设上海专业网站建设价
  • 品牌官方网站蚌埠网站建设文章
  • 做模型的网站有哪些黑龙江省建设工程网
  • 网站建设主流开发语言服装印花图案网站
  • 政务服务网站建设方案wordpress 更改主页
  • 免费发布信息网站大全666面包屑 wordpress
  • 做灯带的网站天津住建网官网
  • 建设银行网站 个人客户端凡科做的网站为什么搜不到
  • 烟台网站营销四川省安监站网址
  • 网站开发外包公司坑怎么做区块链网站