6月30日面试问题

前言

今日面试收集了这些问题,其实我都是有思路的,我把我的思路都讲了出来,只是可能不太完整,有些坑坑巴巴不太理想。

1.多线程的消息队列

我的回答:创建一个队列,把要处理事务放进去先进先出给线程调用

标准回答:消息队列主要是一个队列进行消息存储作为缓冲(削峰填谷),一个锁确保安全访问,一个条件变量用来通知线程

2.多线程访问串口

面试官刚问这个问题的时候我就很奇怪,我听成多个线程访问串口怎么弄,因为我之前做串口方面的没做过这种,把我问懵了,原来是挖了个坑,串口是单通道通信的,压根不支持多个线程并发访问,幸亏没踩上去。

我的回答:用一个线程访问串口,其他的线程要传数据什么的就通过信号传给他

标准回答: 多线程同时读写会导致数据包错乱(如线程A写时线程B打断),通过一个专门的串口控制线程统一管理访问,其他线程通过信号槽机制间接操作

优化方案

 1.线程标识机制,每个请求携带发送者object指针用于结果回传

 2.带超时的非阻塞锁,trylock(50)避免长时间阻塞

 3.请求队列化

// 在SerialController中添加:
QQueue<Request> m_requestQueue; 
QTimer m_processTimer;

void enqueueRequest(Request req) {
    m_requestQueue.enqueue(req);
    if(!m_processTimer.isActive()) 
        m_processTimer.start();
}

void processNext() {
    if(!m_mutex.tryLock()) return;
    if(!m_requestQueue.isEmpty()) {
        auto req = m_requestQueue.dequeue();
        // 处理请求...
    }
    m_mutex.unlock();
}

4.错误恢复机制,串口断开自动重连

connect(m_serial, &QSerialPort::errorOccurred, [=]{
    if(m_serial->error() == QSerialPort::ResourceError) {
        m_serial->close();
        QTimer::singleShot(1000, this, [=]{ 
            if(m_serial->open(QIODevice::ReadWrite)) 
                emit reconnected();
        });
    }
});

 5.批处理机制

将多个小数据包合并发送

void scheduleWrite() {
    if(m_writeBuffer.size() > 512 || m_flushTimer.elapsed() > 50) {
        emit realWrite(m_writeBuffer);
        m_writeBuffer.clear();
    }
}

6.动态优先级队列

给关键请求设置最高优先级

7.数据压缩

使用qcompress处理大流量数据

8.硬件流控启用

m_serial->setFlowControl(QSerialPort::HardwareControl);

3.虚拟内存

我的回答:不知道

标准回答:虚拟内存是一种内存管理技术,它使得应用程序认为自己拥有连续可用的内存(即一个连续完整的地址空间),而实际上,物理内存通常被分割成多个碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。虚拟内存的主要目的包括扩大地址空间、内存保护、共享内存和更好的内存组织管理。

4.多线程条件变量

我的回答:不知道

我的思路:这一块确实忘了,之前研究锁的时候了解过是有一个机制,让资源足够的时候通知工作线程,和信号量搞混了惭愧 

标准回答:条件变量是多线程基于锁的线程同步方法,读线程会处于wait状态,有一个共享变量,写线程修改完了以后回通知一个或多个读线程,通知哪个线程根据系统调度策略不能确定

5.q_object宏是干嘛的,和继承的那个有什么区别

我的回答:有这个宏就可以调用movetothered函数那些,后面混淆了答不出来

标准回答:q_object宏为程序提供了元对象系统,信号与槽机制,动态属性系统,事件和事件过滤器,翻译和国际化这些功能,他会自动解析并创建moc文件。

和继承q_object的区别:继承q_object相当于是一个智能手机,他提供基础的qt对象能力,而q_object宏相当于是应用商店,提供信号槽这些功能可以使用,有宏没继承会报错,有继承没宏不会报错,但是信号槽不能使用

6.时间复杂度和空间复杂度

我的回答:程序运行一个周期所需时间,空间复杂度忘了

标准回答:时间复杂度主要是衡量算法的运行次数,空间复杂度主要是衡量一个算法所需要的额外空间(一个程序需要额外定义变量的个数)

7.cannys函数参数

我的回答:忘了

标准回答

void cv::Canny(
    InputArray image,         // 输入图像(单通道灰度图)
    OutputArray edges,        // 输出边缘图(二值图像,边缘为白色)
    double threshold1,        // 低阈值
    double threshold2,        // 高阈值
    int apertureSize = 3,     // Sobel 算子孔径大小
    bool L2gradient = false   // 梯度计算方式
);

OpenCV 中的 Canny() 函数是经典的边缘检测算法(由 John F. Canny 提出),其核心是通过多阶段处理提取图像中的强边缘。以下是其参数详解及使用指南:


📌 函数原型

void cv::Canny(
    InputArray image,         // 输入图像(单通道灰度图)
    OutputArray edges,        // 输出边缘图(二值图像,边缘为白色)
    double threshold1,        // 低阈值
    double threshold2,        // 高阈值
    int apertureSize = 3,     // Sobel 算子孔径大小
    bool L2gradient = false   // 梯度计算方式
);

🔍 参数深度解析

1. ​**image:输入图像**
  • 要求:必须为 ​8 位单通道灰度图像​(如 CV_8UC1)。
  • 预处理建议
    • 若输入为彩色图,需先转为灰度:cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY)
    • 可先进行高斯模糊降噪:cv::GaussianBlur(gray, blurred, Size(5,5), 0)
2. ​**edges:输出图像**
  • 格式:与输入同尺寸的二值图(CV_8U),边缘像素值为 255(白色),非边缘为 0(黑色)。
3. ​**threshold1threshold2:双阈值**
  • 作用:用于边缘连接的滞后阈值处理。
  • 阈值关系threshold1 < threshold2(否则函数会交换两者)。
  • 工作流程
    graph LR
        A[梯度计算] --> B[非极大值抑制]
        B --> C{梯度值 ≥ threshold2?}
        C -->|是| D[确认为强边缘]
        C -->|否| E{梯度值 ≥ threshold1?}
        E -->|是| F[标记为弱边缘]
        E -->|否| G[抑制]
        D --> H[输出边缘]
        F --> I[与强边缘连通则保留]
  • 经验值
    • 经典比例:threshold2 : threshold1 ≈ 3 : 12 : 1
    • 示例:(100, 200)(50, 150)
  • 调参技巧
    • 高阈值 threshold2 控制主要边缘的完整性(值过高 → 边缘断裂)。
    • 低阈值 threshold1 控制细节边缘的数量(值过低 → 噪声增多)。
4. ​**apertureSize:Sobel 算子孔径**
  • 作用:计算图像梯度时使用的卷积核尺寸。
  • 可选值3, 5, 7(默认=3)。
  • 影响
    • 较大的孔径(如 5 或 7)对噪声更鲁棒,但边缘定位稍模糊。
    • 较小的孔径(如 3)边缘更精细,但对噪声敏感。
  • 注意:在 OpenCV 4.x 中,若需使用 Scharr 算子(更精确的梯度计算),可设 apertureSize = -1
5. ​**L2gradient:梯度幅值计算方式**
  • ​**false(默认)​**:使用 L1 范数(计算快)
    |G| = |G_x| + |G_y|
  • ​**true**:使用 L2 范数(更精确)
    |G| = \sqrt{G_x^2 + G_y^2}
  • 建议
    • 对精度要求高时选 true(如医学图像)。
    • 实时处理追求速度时选 false

8.多线程如何异步

我的回答:使用锁的机制,使资源再一定情况下只能被一个线程访问,感觉和线程同步弄混了

标准回答:消息队列实现 

总结

是不是很拉跨,这些我之前知道,用的太少了,就忘了,还是要温故而知新啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值