《深入浅出MFC》2/e產生㆒個 Worker Thread / 759 產生㆒個 UI Thread / 761 執行緒的結束 / 763 執行緒與同步控制 / 763 MFC 多緒程式實例 / 766 目 錄 25 * 第 15 章 定製㆒個 AppWizard / 771 到底 Wizard 是什麼? Step1-具备Document/View 架构(第8章):本例主旨在加上资料处 理与显示的能力。这一版的窗口没有卷动能力。同一文件的两个显示窗口也没 有能够做到实时更新的效果。当你在窗口甲改变文件内容,对映至同一文件的 窗口乙并不会实时修正内容,必须等WM_PAINT 产生(例如拉大窗口)。 这个版本已具备打印与预视能力,但并非「所见即所得」(What You See Is What You Scribble Step4-加强显示能力- 滚动条与分裂窗口(第11 章):Scribble 可以 对同一份Document 产生一个以上的Views,但有一个缺点亟待克服,那就是 你在窗口A的绘图动作不能实时影响窗口B -- 即使它们是同一份资料的一体 两面! Step4 解决上述问题。主要关键在于我们必须想办法通知所有同血源(同一份 Document)的兄弟(各个Views),让它们一起行动。但因此却必须多考虑一个情况:0 码力 | 1009 页 | 11.08 MB | 1 年前3
Hello 算法 1.0.0b1 C++版为了解决此问题,诞生了一种被称为「列表 List」的数据结构。列表可以被理解为长度可变的数组,因此也常 被称为「动态数组 Dynamic Array」。列表基于数组实现,继承了数组的优点,同时还可以在程序运行中实时 扩容。在列表中,我们可以自由地添加元素,而不用担心超过容量限制。 4.3.1. 列表常用操作 初始化列表。我们通常会使用到“无初始值”和“有初始值”的两种初始化方法。 // === File: 初始容量:选取一个合理的数组的初始容量 initialCapacity 。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:需要声明一个变量 size ,用来记录列表当前有多少个元素,并随着元素插入与删除实时更 新。根据此变量,可以定位列表的尾部,以及判断是否需要扩容。 ‧ 扩容机制:插入元素有可能导致超出列表容量,此时需要扩容列表,方法是建立一个更大的数组来替换 当前数组。需要给定一个扩容倍数 extendRatio 「线性探测」使用固定步长的线性查找来解决哈希冲突。 插入元素:如果出现哈希冲突,则从冲突位置向后线性遍历(步长一般取 1 ),直到找到一个空位,则将元素 插入到该空位中。 查找元素:若出现哈希冲突,则使用相同步长执行线性查找,会遇到两种情况: 1. 找到对应元素,返回 value 即可; 2. 若遇到空位,则说明查找键值对不在哈希表中; Figure 6‑5. 线性探测 线性探测存在以下缺陷: ‧0 码力 | 187 页 | 14.71 MB | 1 年前3
Hello 算法 1.0.0b2 C++版为了解决此问题,诞生了一种被称为「列表 List」的数据结构。列表可以被理解为长度可变的数组,因此也常 被称为「动态数组 Dynamic Array」。列表基于数组实现,继承了数组的优点,同时还可以在程序运行中实时 扩容。在列表中,我们可以自由地添加元素,而不用担心超过容量限制。 4.3.1. 列表常用操作 初始化列表。我们通常会使用到“无初始值”和“有初始值”的两种初始化方法。 // === File: 初始容量:选取一个合理的数组的初始容量 initialCapacity 。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:需要声明一个变量 size ,用来记录列表当前有多少个元素,并随着元素插入与删除实时更 新。根据此变量,可以定位列表的尾部,以及判断是否需要扩容。 ‧ 扩容机制:插入元素有可能导致超出列表容量,此时需要扩容列表,方法是建立一个更大的数组来替换 当前数组。需要给定一个扩容倍数 extendRatio 「线性探测」使用固定步长的线性查找来解决哈希冲突。 插入元素:如果出现哈希冲突,则从冲突位置向后线性遍历(步长一般取 1 ),直到找到一个空位,则将元素 插入到该空位中。 查找元素:若出现哈希冲突,则使用相同步长执行线性查找,会遇到两种情况: 1. 找到对应元素,返回 value 即可; 2. 若遇到空位,则说明查找键值对不在哈希表中; Figure 6‑5. 线性探测 线性探测存在以下缺陷: 60 码力 | 197 页 | 15.72 MB | 1 年前3
Hello 算法 1.0.0b4 C++版。需要关注三个核心点: ‧ 初始容量:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:声明一个变量 size,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据此 变量,我们可以定位列表尾部,以及判断是否需要扩容。 ‧ 扩容机制:插入元素时可能超出列表容量,此时需要扩容列表。扩容方法是根据扩容倍数创建一个更大 的数组,并将当前数组的所有元素 操作方法为: ‧ 插入元素:通过哈希函数计算数组索引,若发现桶内已有元素,则从冲突位置向后线性遍历(步长通常 为 1 ),直至找到空位,将元素插入其中。 ‧ 查找元素:若发现哈希冲突,则使用相同步长向后线性遍历,直到找到对应元素,返回 value 即可;如 果遇到空位,说明目标键值对不在哈希表中,返回 None 。 Figure 6‑6. 线性探测 然而,线性探测存在以下缺陷: ‧ {4, 5} 和 {5, 4} 是同一个子集。 13. 回溯 hello‑algo.com 260 参考全排列解法 类似于全排列问题,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素 和”,当元素和等于 target 时,就将子集记录至结果列表。 而与全排列问题不同的是,本题集合中的元素可以被无限次选取,因此无需借助 selected 布尔列表来记录元 素是否已0 码力 | 343 页 | 27.39 MB | 1 年前3
Hello 算法 1.1.0 C++ 版括以下三个重点设计。 ‧ 初始容量:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:声明一个变量 size ,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据 此变量,我们可以定位列表尾部,以及判断是否需要扩容。 ‧ 扩容机制:若插入元素时列表容量已满,则需要进行扩容。先根据扩容倍数创建一个更大的数组,再将 当前数组的所有元素依次移动至新 通哈希表有所不同。 ‧ 插入元素:通过哈希函数计算桶索引,若发现桶内已有元素,则从冲突位置向后线性遍历(步长通常为 1 ),直至找到空桶,将元素插入其中。 ‧ 查找元素:若发现哈希冲突,则使用相同步长向后进行线性遍历,直到找到对应元素,返回 value 即 可;如果遇到空桶,说明目标元素不在哈希表中,返回 None 。 图 6‑6 展示了开放寻址(线性探测)哈希表的键值对分布。根据此哈希函数,最后两位相同的 和 {5, 4} 是同一个子集。 第 13 章 回溯 hello‑algo.com 289 1. 参考全排列解法 类似于全排列问题,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素 和”,当元素和等于 target 时,就将子集记录至结果列表。 而与全排列问题不同的是,本题集合中的元素可以被无限次选取,因此无须借助 selected 布尔列表来记录元 素是否已0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.0.0b5 C++版包括以下三个重点设计。 ‧ 初始容量:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:声明一个变量 size,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据此 变量,我们可以定位列表尾部,以及判断是否需要扩容。 ‧ 扩容机制:若插入元素时列表容量已满,则需要进行扩容。首先根据扩容倍数创建一个更大的数组,再 将当前数组的所有元素依次移动至 表有所不同。 ‧ 插入元素:通过哈希函数计算数组索引,若发现桶内已有元素,则从冲突位置向后线性遍历(步长通常 为 1 ),直至找到空位,将元素插入其中。 ‧ 查找元素:若发现哈希冲突,则使用相同步长向后线性遍历,直到找到对应元素,返回 value 即可;如 果遇到空位,说明目标键值对不在哈希表中,返回 None 。 图 6‑6 展示了一个在开放寻址(线性探测)下工作的哈希表。 第 6 章 和 {5, 4} 是同一个子集。 第 13 章 回溯 hello‑algo.com 292 1. 参考全排列解法 类似于全排列问题,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素 和”,当元素和等于 target 时,就将子集记录至结果列表。 而与全排列问题不同的是,本题集合中的元素可以被无限次选取,因此无须借助 selected 布尔列表来记录元 素是否已0 码力 | 377 页 | 30.69 MB | 1 年前3
Hello 算法 1.0.0 C++版括以下三个重点设计。 ‧ 初始容量:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:声明一个变量 size ,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据 此变量,我们可以定位列表尾部,以及判断是否需要扩容。 ‧ 扩容机制:若插入元素时列表容量已满,则需要进行扩容。先根据扩容倍数创建一个更大的数组,再将 当前数组的所有元素依次移动至新 通哈希表有所不同。 ‧ 插入元素:通过哈希函数计算桶索引,若发现桶内已有元素,则从冲突位置向后线性遍历(步长通常为 1 ),直至找到空桶,将元素插入其中。 ‧ 查找元素:若发现哈希冲突,则使用相同步长向后进行线性遍历,直到找到对应元素,返回 value 即 可;如果遇到空桶,说明目标元素不在哈希表中,返回 None 。 图 6‑6 展示了开放寻址(线性探测)哈希表的键值对分布。根据此哈希函数,最后两位相同的 和 {5, 4} 是同一个子集。 第 13 章 回溯 hello‑algo.com 291 1. 参考全排列解法 类似于全排列问题,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素 和”,当元素和等于 target 时,就将子集记录至结果列表。 而与全排列问题不同的是,本题集合中的元素可以被无限次选取,因此无须借助 selected 布尔列表来记录元 素是否已0 码力 | 378 页 | 17.59 MB | 1 年前3
Hello 算法 1.2.0 简体中文 C++ 版括以下三个重点设计。 ‧ 初始容量:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。 ‧ 数量记录:声明一个变量 size ,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据 此变量,我们可以定位列表尾部,以及判断是否需要扩容。 ‧ 扩容机制:若插入元素时列表容量已满,则需要进行扩容。先根据扩容倍数创建一个更大的数组,再将 当前数组的所有元素依次移动至新 通哈希表有所不同。 ‧ 插入元素:通过哈希函数计算桶索引,若发现桶内已有元素,则从冲突位置向后线性遍历(步长通常为 1 ),直至找到空桶,将元素插入其中。 ‧ 查找元素:若发现哈希冲突,则使用相同步长向后进行线性遍历,直到找到对应元素,返回 value 即 可;如果遇到空桶,说明目标元素不在哈希表中,返回 None 。 图 6‑6 展示了开放寻址(线性探测)哈希表的键值对分布。根据此哈希函数,最后两位相同的 4} 是同一个子集。 第 13 章 回溯 www.hello‑algo.com 289 1. 参考全排列解法 类似于全排列问题,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素 和”,当元素和等于 target 时,就将子集记录至结果列表。 而与全排列问题不同的是,本题集合中的元素可以被无限次选取,因此无须借助 selected 布尔列表来记录元 素是否已0 码力 | 379 页 | 18.48 MB | 10 月前3
C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程?稍后会说明。 • 运行以后,就会在 GPU 上执行 printf 了。 • 这里的 kernel 函数在 GPU 上执行,称为核 函数,用 __global__ 修饰的就是核函数。 没有反应?同步一下! • 然而如果直接编译运行刚刚那段代码,是不会打印出 Hello, world! 的。 • 这是因为 GPU 和 CPU 之间的通信,为了高效,是异 步的。也就是 CPU 调用 kernel<<<1 里的板块数和线程数可以动态指定,无需 先传回到 CPU 再进行调用,这是 CUDA 特有的能力。 常用于这种情况:需要从 GPU 端动态计算出 blockDim 和 gridDim ,而又不希望导回数据到 CPU 导致强制同步影响性能。 这种模式被称为动态并行( dynamic parallelism ), OpenGL 有一 个 glDispatchComputeIndirect 的 API 和这个很像,但毕竟没有 CUDA cudaMemcpyDeviceToHost 。 • 同理,还有 cudaMemcpyHostToDevice 和 cudaMemcpyDeviceToDevice 。 cudaMemcpy 会自动同步! • 注意: cudaMemcpy 会自动进行同步操作 ,即和 cudaDeviceSynchronize() 等价! 因此前面的 cudaDeviceSynchronize() 实 际上可以删掉了。 统一内存地址技术(0 码力 | 142 页 | 13.52 MB | 1 年前3
现代C++ 教程:高速上手C++11/14/17/20需要结果的时候,调用一个线程等待函数来获得执行的结果。 而 C++11 提供的 std::future 简化了这个流程,可以用来获取异步任务的结果。自然地,我们很 容易能够想象到把它作为一种简单的线程同步手段,即屏障(barrier)。 为了看一个例子,我们这里额外使用 std::packaged_task,它可以用来封装任何可以调用的目标, 从而用于实现异步的调用。举例来说: #include result.get() << std::endl; return 0; } 在封装好要调用的目标后,可以使用 get_future() 来获得一个 std::future 对象,以便之后实施 线程同步。 7.4 条件变量 条件变量 std::condition_variable 是为了解决死锁而生,当互斥操作不够用而引入的。比如,线程 可能需要等待某个条件为真才能继续执行,而一个忙等待循环中可能会导致所有其他线程都无法进入临 提供线程间自动的状态转换,即『锁住』这个状态 2. 保障在互斥锁操作期间,所操作变量的内存与临界区外进行隔离 这是一组非常强的同步条件,换句话说当最终编译为 CPU 指令时会表现为非常多的指令(我们之 后再来看如何实现一个简单的互斥锁)。这对于一个仅需原子级操作(没有中间态)的变量,似乎太苛刻 了。 关于同步条件的研究有着非常久远的历史,我们在这里不进行赘述。读者应该明白,现代 CPU 体系 结构提供了 CPU0 码力 | 83 页 | 2.42 MB | 1 年前3
共 14 条
- 1
- 2













