使用两个队列,改进耗时线程引起的性能问题的思路及代码

简介: 使用两个队列,改进耗时线程引起的性能问题的思路及代码

线程冲突很常见。有效的解决办法,就是使用线程锁。


 吾现在碰到一个问题:


多个数据线程向一个队列中添加数据。

一个执行线程负责处理队列中的数据。

 开始使用线程锁,也没有问题。后来仔细想了一下,觉得此处有阻塞问题:


执行线程消耗时间较多,在执行前加锁,执行完毕后释放锁。

在执行线程加锁期间,数据线程等着向队列中添加数据,岂不是要等较长时间?

 怎么办?吾想了个办法。原有代码保持不变,执行线程自己增加一个执行元素(用不着执行队列)。于是流程变为:


执行线程执行前,加锁。

将数据队列中最先加入的元素,复制成执行元素。

解锁。

执行线程处理执行元素。

 这样不仅实现了线程安全,也保证各个线程的性能。实例代码如下:


/**
因为FEXT消耗时间较长,所以采取两个队列:
一个用来加数据,通过线程锁控制。
一个复制后,执行Fext
*/
static  ImageBuffer**   g_ppFextQueue      = NULL;
static  int             g_nFextQueueLength = -1;
static  pthread_mutex_t g_oFextMutext;
static  void  fext_queue(ImageBuffer* pImage)
{
    int queued = 0;
    //>=0表示初始化完成。
    if (g_nFextQueueLength >= 0)
    {
        pthread_mutex_lock(&g_oFextMutext);
     if (g_nFextQueueLength >= GH_FEXT_QUEUE_LENGTH)
        {
            g_nFextQueueLength = 0;
        }
        //注意结构体内部的指针问题
        memcpy(g_ppFextQueue[g_nFextQueueLength], pImage, sizeof(ImageBuffer));
        g_nFextQueueLength ++;
        queued = 1;
        pthread_mutex_unlock(&g_oFextMutext);
    }
    if (!queued)
    {
        databuffer_release((DataBuffer*)&(pImage->buffer));
    }
}
static  void  *fext_thread(void  *arg)
{
    int i;
    ImageBuffer*   pFextExe       = NULL;
    int queue_malloc_size = sizeof(ImageBuffer*)*GH_FEXT_QUEUE_LENGTH;
    //开始初始化,fext_queue()不会进行相应操作。
    g_nFextQueueLength = -1;
    fext_init(  (char*)arg);
    //free(arg);
    //fext初始化开始
    pthread_mutex_init(&g_oFextMutext, NULL);
    g_ppFextQueue   =  (ImageBuffer**)gh_malloc(queue_malloc_size);
    for (i=0; i<GH_FEXT_QUEUE_LENGTH; i++)
    {
        g_ppFextQueue[i]  = (ImageBuffer*)gh_malloc(sizeof(ImageBuffer));
    }
    pFextExe = (ImageBuffer*)gh_malloc(sizeof(ImageBuffer));
    //fext初始化完成
    g_nFextQueueLength  = 0;
    DataBuffer oImageFeature;
    memset(&oImageFeature, 0, sizeof(DataBuffer));
    databuffer_check(&oImageFeature, sizeof(float)*GH_FEXT_FEATURE_SIZE);
    while  (1)
    {
      if  (g_nFextQueueLength == 0)
      {
          usleep(GH_FEXT_THREAD_SLEEP_TIME);
          continue;
      }
      //将数据队列的指针复制到执行队列。      
      pthread_mutex_lock(  &g_oFextMutext);
      int early_index = g_nFextQueueLength + 1; //注意越界处理
      memcpy(pFextExeQueue, g_ppFextQueue[early_index], sizeof(ImageBuffer));
      g_nFextQueueLength  = 0;
      pthread_mutex_unlock(&g_oFextMutext);
      fext_action(pImage, &oImageFeature);
    }
    //做个样子而已。
    databuffer_release(&oImageFeature);
    free_array(g_ppFextQueue, GH_FEXT_QUEUE_LENGTH);
    free(g_ppFextQueue);
    free(pFextExeQueue);
}
目录
相关文章
|
3月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
112 1
|
12天前
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
26 7
|
12天前
|
消息中间件 存储 安全
|
2月前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
|
1月前
|
存储 运维 API
源码解密协程队列和线程队列的实现原理(一)
源码解密协程队列和线程队列的实现原理(一)
35 1
|
1月前
|
存储 安全 API
源码解密协程队列和线程队列的实现原理(二)
源码解密协程队列和线程队列的实现原理(二)
33 1
|
3月前
|
存储 监控 Java
|
3月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
3月前
|
数据采集 Java Python
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
|
3月前
|
Java 开发者
解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!
【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。
42 0

相关实验场景

更多