avatar
文章
104
标签
18
分类
8

首页
归档
标签
分类
列表
  • 音乐
  • 视频
友链
关于
编程随笔
搜索
首页
归档
标签
分类
列表
  • 音乐
  • 视频
友链
关于

编程随笔

C++并发和同步
发表于2023-04-02|C++|C++多线程
1. 概述 C++标准的同步工具: 条件变量 std::condition_variable std::condition_variable_any future latch barrier Qt中的对应物: QWaitCondition QFuture QPromise QFutureSynchronizer QFutureWatcher 2. 条件变量条件变量必须配合互斥量一起使用.两个条件变量: std::condition_variable: 必须配合std::mutex一起使用. std::condition_variable_any: 只要某一类型符合称为互斥量的最低标准, 就可以使用. 条件变量有notify_one()和notify_all()两个方法, 适用于不同的场景. 有些特定的情况下, 可能std::call_once()更简单, 使用条件变量过于复杂. 例如初始化 若线程只需要等待一次, 可能使用future更合适. 在生产者中, 生产后用条件变量的notify_one()通知消费者 在消费者中: 先用std::uni ...
C++互斥量和锁的使用
发表于2023-04-02|C++|C++多线程
概述 C++标准库中的互斥量和锁 std::lock std::scoped_lock std::unique_lock std::shared_lock std::recursive_mutex std::shared_mutex std::shared_timed_mutex std::shared_lock Qt中的对应物 QMutex QRecursiveMutex QMutexLocker QReadWriteLock QReadLocker QWriteLocker 接口设计设计接口的时候, 要注意接口存在的固有的条件竞争, 设计的接口要注意这个情况. 避免相关的两个接口调用之间的数据状态发生变化. 例如, 一个队列, 如果定义了front()来查询队列首部元素, 提供pop()来修改队列. 这两个接口就会导致这种情况: 如果我们先调用front(), 再pop(), 在多线程情况下就容易出现不一致的情况, 除非我们在外部再做互斥保护. 1. 死锁和保护措施1.1 基本原则:如果能按照相同的顺序加锁解锁, 可以从根本上避免死锁 只要一个线程 ...
生产者和消费者的实现
发表于2023-03-18|C++|并发和多线程
生产者和消费者这里讨论多线程下的生产者消费者, 尤其是多生产者-单消费者模式. 单线程的生产者-消费者模式最好的语法糖是协程. 这个以后再说. 1. C++/Qt生产者-消费者问题, 基本的模式是需要有一个共享的数据结构, 生产者向里面加入数据, 消费者从里面取出数据. 在多线程/多进程模式下, 要考虑的问题有两点: 数据保护 状态的通知 在绝大多数工程场景下, 我们一般不用考虑公共缓冲区的大小, 也就是假定生产者可以不受约束的向里面加入数据. 那么剩下的问题就是消费者. 最简单的做法, 就是网上大部分的例子一样, 一个忙等待: 123456789while(true){ mutex.lock(); if(!buffer.empty()) { // .... } mutex.unlock();} 这样的问题在于, 消费者线程是没有被阻塞的, 即使是队列为空, 消费者线程也是在不断地轮询检查, 始终占用CPU资源. 尤其是消耗互斥量内核资源. 我们真正需要的模式应该是这样 ...
获取外接矩形和内接矩形
发表于2022-11-17|OpenCV|算法
获取外接矩形和内接矩形我们有两种需要构造内接矩形的场景: 一种是使用扫描仪做连续扫描的场景. 在这种情况下, 拼接之后的大图本身就是比较规整的矩形, 我们其实并不需要真正寻找内接矩形的操作, 只需要将外围截掉一定的大小, 就可以得到一个完美的矩形. 我们使用M*N的方式来计算左上角和右下角需要向内收缩的尺寸, M是行/列方向上的视野的个数, N一般取30个像素就绰绰有余了. 为了弥补由于截断丢失的内容, 我们只需要在扫描的时候将扫描区域外扩做一下补偿即可. 另一种情况是手工操作显微镜连续拍摄的情况. 在这种情况下, 用户最终会扫出一个什么形状完全不可控, 就只能计算内接矩形了. 获取外接矩形外接矩形十分简单, 只要计算一下boundingRect就可以得到. 没有太多需要讨论的. 获取内接矩形下面使用的算法是一个比较直观易懂的算法, 没有进行优化. 我们构造一个和要检测的图像等尺寸的矩形leftMat, 用于保存要处理的图像中每个像素左边的非零像素的个数.然后, 再遍历leftMat, 统计每个位置上面的每个像素, 获取能够组成的最大的矩形. 我们要处理的图像 ...
可变参数模板在C++17中的增强
发表于2022-11-12|C++|C++ Template
可变参数模板在C++17中的增强基本内容可变参数模板, 称作variadic, 在C++11中就引入了, 但是那个时候需要人工编写递归表达式. 在C++中对此进行了增强. 因此, 在绝大多数情况下, 不需要再通过人工编写递归表达式, 简化了开发. 比如, 下面这个求和的函数: 12345template<typename... T>auto foldSum(T... args){ return (... + args);} 在C++17之前, 我们需要这么实现: 1234567891011template<typename... T>auto foldSum(T arg){ return arg;}template<typename T1, typename... Ts>auto foldSum(T1 arg1, Ts... args){ return arg1 + foldSum(args);} 不过就我个人来看, 其实还是老的模式更容易理解一些. 新的方式下还要 ...
游戏之作-QVariant的解析和更新
发表于2022-11-07|Qt|设计笔记
游戏之作: QVariant的解析和更新纯属好玩的实现. 我有一个很大的数据结构, 有很多的成员变量, 几十个. 中间涉及到更新, 更新的数据源是外部传过来的一个json对象, 被解析为一个QVariantMap或QVariantHash. 对于每个属性, 我们需要判断传进来的Map中有没有包含, 如果包含了, 还要判断是否有意义(例如, 对QString, 是否为空). 只有都满足了, 才会使用它来更新结构中的属性. 属性类型包括整数, 浮点数, 日期类型, 字符串和QByteArray码流. 这里一个很麻烦的问题是, 比如, QString, QDate, 判断值有效性是不同的函数. QString和QByteArray是isEmpty(), 而QDate和QDateTime则是isValid(). 如果每个都使用if...else判断, 实在太麻烦, 还要记住每个成员的类型. 这个问题只有C++能够给出令人满意的解决方案. 实现0:可以用宏实现. 这里主要的问题是需要自己处理类型. 仍然需要记住每个变量的转换函数. 在C++11之前, 大概只能这么实现. 实现1:利用C++ ...
游戏之作-Restful命令处理对象
发表于2022-11-07|Qt|设计笔记
游戏之作: Restful命令处理对象我们的产品有几十条Restful命令, 凭心而林, 命令太多, 不正交. 更大的问题是命令的api更杂乱.对上层代码而言, 屏蔽Restful命令差异的方式当然是封装接口函数. 但是为每一个函数封装一个接口, 又有大量的样板代码. 虽然前期我是这么做的, 但是随着接口越来越多, 也越来越让人感到厌烦.比如, 下面是一条命令的实现: 12345678910111213141516171819202122232425262728bool KaryoServices::modifyCaseInfo(const QString &case_id, const QVariantMap &info){ QJsonObject rsp; QJsonObject param = QJsonObject::fromVariantMap(info); TRACE() << param; QString path = QString("/api/case/%1").arg(case_id) ...
MagicTool的实现
发表于2022-10-05|Karyotype|设计笔记
MagicTool实现MagicTool为仿照某产品的实现而提供的功能, 目的是尽量减少使用者切换工具的操作, 能够利用鼠标以不同的操作手势来实现不同的行为. 规格:按下Magic按钮, 进入Magic模式. 染色体修型/切割: 在背景上按下鼠标, 画线经过一个染色体, 并在背景上释放鼠标.将经过的第一个染色体拆分, 并抛弃小于阈值的部分. 识别: flyovers.size>=3. 从染色体外起步 从染色体外结束 中间经过至少一个染色体 要切割的就是遇到的第一个染色体 染色体增补: 在一个染色体内部按下鼠标, 拖动鼠标到这个染色体外部区域, 描绘区域再回到这个染色体放开鼠标.将鼠标围起来的染色体外部的区域叠加到染色体上面. 从染色体里面进入 进入其他的染色体或背景 从同一个染色体结束 连接染色体: 在染色体内部按下鼠标, 移动鼠标到相邻的另一个染色体量两个染色体连接到一起. 从一个染色体内部开始 经过其他的染色体和空白 在另一个染色体内结束 分割染色体: 在一个染色体内部按下鼠标, 在这个染色体内部移动鼠标并画一个封闭区域, 然后松开鼠标. ...
看图工具ImageView的设计与实现
发表于2022-09-27|Karyotype|设计笔记
看图工具ImageView的设计与实现1 概述干镜扫描出来的是一个包含数千张甚至数万张高分辨率图片组成的图像数据. 在查看时, 我们不可能一次性的加载所有的图像去显示, 只能使用滑动窗口的方式, 仅加载当前显示的部分, 并且释放掉已经不再需要查看的图像数据, 以节省内存的占用. 目前的版本是从本地获取图像数据,以后要考虑数据存储在网络上的情况。 我们使用金字塔方式的文件结构, 逐级构造出金字塔方式的档案文件. 我们后来才查找到TIFF也支持类似的存储方式, 但是找不到详细的资料, 而且也没有能够直接使用的图像显示操作控件, 所以最终还是自己从头实现. 2. 基本架构ImageView核心由及部分组成: ImageView, 是QGraphicsView的一个派生类, 用于显示图片 TiledPixmapItem, 是QGraphicsItem的子类, 用于显示一张Tile的Item ImageProvider, 用于封装瓦片文件的按需读取 3. 基本实现思路实现的基本思路是利用了Qt的QGraphicsScene/QGraphicsView的机制. 在Scene ...
Marshal的设计
发表于2022-09-25|CellScaner|设计笔记
ImageMatcher设计与实现1. 概述干镜的扫描软件需要做连续扫描, 并将结果拼接成一张完整的大图形式. 涉及到几个难点: 图像数据量很大. 最低的20倍镜头, 扫描玻片全片大约是2200张图片. 40倍则是接近10000张, 100倍则是6万张上下. 每张图片是2448x2048的分辨率, 24bit彩色图像, 原始数据是15M上下. 扫描仪扫描图片的速度是极快的, 以20倍扫描为例, 2200张图片大约90秒就能够完成扫描. 总的数据量超过了30G, 已经超过了电脑的内存大小. 如果再加上其他过程需要的内存, 完全会将系统撑死. 因此, 图片的处理必须能够尽量跟的上扫描的速度. 图像的拼接. 扫描仪的硬件精度不是很好, 在运行扫描过程中, 帧与帧之间大约又±50个像素的误差, 因此无法直接利用硬件(步进电机)的位置作为拼接, 只能作为一个拼接的基准值, 使用图像匹配的方式来做精确的匹配. 而图像匹配的速度是相对比较慢的. 比如想尽一切办法来进行优化. 甚至, 我们都要想办法来尽量拖慢扫描仪的扫描进度(因为它不归我们控制, 我们不好对第三方提出减慢扫描速度的要求). 扫 ...
1…567…11
avatar
ivei@qq.com
好记性不如烂笔头
文章
104
标签
18
分类
8
Follow Me
公告
This is my Blog
最新文章
Qt的GCC和LLVM版本编译promote组件失败的处理2024-10-24
iconfont图标字体Windows下不能用2024-10-23
对RESTful Server的支持类2024-10-02
坑人的题目2024-09-09
简单的QDebug的封装2024-08-20
分类
  • C#3
  • C++37
  • CellScaner1
  • Karyotype6
  • OpenCV1
  • Qt39
  • 图像处理1
  • 形式化11
标签
并发和多线程 形式化可信设计 std Qt随笔 stl和boost C++ C++基础 Mvvm C++多线程 Qt开发实战 VTK 算法 设计笔记 Prism Qt备忘录 Qt C++设计模式 C++ Template
归档
  • 十月 20243
  • 九月 20241
  • 八月 20243
  • 七月 20241
  • 六月 20246
  • 五月 20247
  • 四月 202419
  • 三月 20244
网站资讯
文章数目 :
104
本站访客数 :
本站总访问量 :
最后更新时间 :
©2020 - 2024 By ivei@qq.com
框架 Hexo|主题 Butterfly
沪ICP备2024072223号-1
搜索
数据库加载中