首页 > 其他分享 >OPEN_CV多线程线程池管理

OPEN_CV多线程线程池管理

时间:2024-06-03 20:10:16浏览次数:20  
标签:cond 互斥 线程 pthread mutex 多线程 OPEN CV

两种自旋锁的设置

  1. 操作系统级别自旋锁的设置, 例如在C++11及以后的版本中, 自带线程管理库, 可以定义为: define CV_YIELD() std::this_thread::yield(), 此时进入CV_YIELD(), 线程释放CPU, 线程被阻塞, 等待被唤醒.
  2. CPU级别的自旋锁的设置, 与使用的CPU架构有关, 以X86为例, X86对应的汇编代码如下: static inline void cv_non_sse_mm_pause() { __asm__ __volatile__ ("rep; nop"); }, 使用一个内联函数 cv_non_sse_mm_pause, 然后重复不断的执行nop, 即进行CPU占用的忙等待.

线程体的两种等待形式

主动等待

主动等待的目的

当该线程被创建, 线程获取CPU之后, 还未收到has_wake_signal, (未收到可以开始执行的信号), 此时, 线程并不会直接释放CPU, 而是会忙等一定的时间, 这个时间与参数OPENCV_THREAD_POOL_ACTIVE_WAIT_WORKER成正比. 这样做, 用户可以选择配置忙等的时间, 可以更加灵活的使用CPU.

主动等待的过程

主动等待循环的次数 CV_WORKER_ACTIVE_WAIT 就是环境变量OPENCV_THREAD_POOL_ACTIVE_WAIT_WORKER, 在未达到循环次数时, 调用 CPU 的自旋锁, 使线程陷入忙等, 在达到循环次数之后, 调用操作系统的自旋锁, 线程被阻塞.

// 主动等待
CV_LOG_VERBOSE(NULL, 5, "Thread: ... loop iteration: allow_active_wait=" << allow_active_wait << "   has_wake_signal=" << has_wake_signal);
// 如果允许忙等, 并且设置的环境变量 OPENCV_THREAD_POOL_ACTIVE_WAIT_WORKER > 0
if (allow_active_wait && CV_WORKER_ACTIVE_WAIT > 0)
{
    allow_active_wait = false;
    // 在 OPENCV_THREAD_POOL_ACTIVE_WAIT_WORKER 时间内忙等资源, 实际上是等待收到信号 has_wake_signal
    for (int i = 0; i < CV_WORKER_ACTIVE_WAIT; i++)
    {
        // 如果已经收到唤醒信号, 表示可以开始执行任务, 退出循环
        if (has_wake_signal)
            break;
        if (CV_ACTIVE_WAIT_PAUSE_LIMIT > 0 && (i < CV_ACTIVE_WAIT_PAUSE_LIMIT || (i & 1)))
            CV_PAUSE(16);
        else
            CV_YIELD();
    }
}

被动等待

被动等待的实现方式是使用互斥锁, 配合C++多线程中的 pthread_cond_wait 方法. 使用条件变量与互斥锁, 这种方式的好处是:

  1. 避免互斥锁的忙等待(互斥锁只能忙等)
  2. 简化同步逻辑, 以及高效的线程唤醒.

多线程条件变量等待pthread_cond_wait与互斥锁的配合使用

条件变量是利用线程间共享的全局变量进行同步的一种机制, 主要包括两个动作:

  1. 一个线程等待"条件变量的条件成立"而挂起;
  2. 另一个线程使"条件成立"(给出条件成立信号).
    为了防止竞争, 条件变量的使用总是和一个互斥锁结合在一起, 这样既可以避免了直接使用互斥锁导致的忙等, 也可以实现资源的同步, 防止资源使用冲突.

使用模板

互斥锁与条件变量的声明
// 声明全局变量
// 线程互斥锁
pthread_mutex_t mutex;
// 线程资源等待条件变量
pthread_cond_t  q_ready;
// 初始化
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&q_ready, NULL);

等待资源的线程

pthread_mutex_t qlock;
pthread_cond_t  qready;
/************pthread_cond_wait()的使用方法**********/
pthread_mutex_lock(&mutex);    /*lock*/
// 等待某资源,并以q_ready作为条件通知我们
pthread_cond_wait(&q_ready, &mutex); /*block-->unlock-->wait() return-->lock*/
// 修改互斥锁 mutex 保护的资源
pthread_mutex_unlock(&qlock); /*unlock*/

释放资源的线程

// 被动等待开始, 获取互斥锁
pthread_mutex_lock(&mutex);
#ifdef CV_PROFILE_THREADS
stat.threadWait = getTickCount();
#endif       
// 进入循环等待, 等待收到唤醒信号 has_wake_signal
while (!has_wake_signal) // to handle spurious wakeups
{
    //CV_LOG_VERBOSE(NULL, 5, "Thread: wait (sleep) ...");
// 如果使用全局的唤醒信号
#if defined(CV_USE_GLOBAL_WORKERS_COND_VAR)
    pthread_cond_wait(&thread_pool.cond_thread_wake, &mutex);
#else
    isActive = false;
    // 这里会释放CPU资源, 然后等待环境变量, 同时释放互斥锁, 
    pthread_cond_wait(&cond_thread_wake, &mutex);
    isActive = true;
#endif
    CV_LOG_VERBOSE(NULL, 5, "Thread: wake ... (has_wake_signal=" << has_wake_signal << " stop_thread=" << stop_thread << ")")
}
#ifdef CV_PROFILE_THREADS
stat.threadWake = getTickCount();
#endif

CV_LOG_VERBOSE(NULL, 5, "Thread: checking for new job");
if (CV_WORKER_ACTIVE_WAIT_THREADS_LIMIT == 0)
    allow_active_wait = true;
Ptr<ParallelJob> j_ptr; swap(j_ptr, job);
has_wake_signal = false;    // 资源已经获取完成, 可以开始执行
pthread_mutex_unlock(&mutex);

标签:cond,互斥,线程,pthread,mutex,多线程,OPEN,CV
From: https://www.cnblogs.com/wevolf/p/18229545

相关文章

  • Java 多线程的创建
    Java多线程的创建Java元的JVM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类线程的创建方式有两种,一者为继承Thread类,一者为实现Runnable接口实现方式之一:继承Thread类实现步骤Java通过继承Thread类来创建并启动多线程......
  • 云渲染农场什么是线程模式?
    ​许多设计师在选择云渲染农场时,常常会遇到48线程、56线程、72线程等选项,然而,不少新手在面对这些选择时,往往无法直观地感受到不同线程数量之间的差异。接下来,我们将共同探讨线程的作用和影响,帮助大家更好地理解这些选择。一、CPU线程的意思CPU线程是计算机处理器的基本工作单元......
  • 面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
    优雅的关闭线程池我们现在步入正题,来看一看在线程池使用完成后如何优雅的关闭线程池。在JDK1.8中,Java并发工具包中java.util.concurrent.ExecutorService提供了shutdown()、shutdownNow()这两种接口方法去关闭线程池,我们分别看一下。shutdown()publicvoidshutdo......
  • ABC 312 F Cans and Openers
    题意现在有三种物品,给出的格式为(t[i],x[i])如下:拉环罐头,被标记为t[i]=0,得到即食,可以得到x[i]的开心值。普通罐头,被标记为t[i]=1,需要用开罐器打开,食用后可以得到x[i]的开心值。开罐器,被标记为t[i]=2,使用后可以打开x[i]个普通罐头。现在有N个这样的物品,你可以选择其中的......
  • opencv c++编程基础
    1、图片的本质图像在OpenCV中的本质在OpenCV中,图像被表示为一个多维数组,其中每个元素对应于图像中的单个像素。图像的维度取决于其通道数和像素数。**通道数:**图像可以有多个通道,每个通道存储图像的不同信息。例如,彩色图像通常有3个通道(红色、绿色和蓝色),而灰度图像只......
  • C++实现线程池详解
    在现代软件开发中,高效地管理和利用计算资源是一项关键任务。线程池(ThreadPool)是一种非常有效的并发编程技术,它允许我们管理和重用一组线程,从而避免频繁创建和销毁线程带来的性能开销。1.线程池的基本概念线程池是一组预先创建的线程,这些线程等待并执行任务。当任务到达时,它......
  • Java多线程
    线程的定义Java线程是Java编程语言中的执行单元。在Java中,线程可以看作是轻量级的进程,它独立运行,具有自己的执行路径。线程的原理Java线程的实现基于操作系统的线程模型,但Java虚拟机(JVM)对线程的管理和调度做了封装和优化,使得Java线程更加可控和可靠。下面是Java线程的一些基本......
  • git 命令报错:Another git process seems to be running in this repository, e.g. an
    执行git命令时,报错:Anothergitprocessseemstoberunninginthisrepository,e.g.aneditoropenedby'gitcommit'.Pleasemakesureallprocessesareterminatedthentryagain.Ifitstillfails,agitprocessmayhavecrashedinthisrepository......
  • centos下 openssl 生成局域网ip的https证书
    环境准备利用OpenSSL签发证书需要OpenSSL软件及库,一般情况下CentOS、Ubuntu等系统均已内置,可执行openssl确认,如果提示oepnssl:commandnotfound,则需手动安装,以Centos为例:yuminstallopensslopenssl-devel-y生成证书请求文件新建openssl.cnf,内容如下:[req......
  • OpenCV 的几种查找图像中轮廓边缘的方法
     原始图片: 1、Sobel()Sobel算子结合了高斯平滑和微分,用于计算图像的梯度,从而突出显示边缘。importcv2#读取图像image=cv2.imread('image.png',cv2.IMREAD_GRAYSCALE)#使用Sobel算子查找水平和垂直边缘sobel_x=cv2.Sobel(image,cv2.CV_64F,1,0,ksize......