c++中的线程池设计

thread pool design in C++

本文关键字:线程 c++      更新时间:2023-10-16

我不知道如何把这个问题放在这个论坛上,我问的任何方式,希望得到一些输入。

我正在为我的项目写线程池。我有以下设计。

  1. 我正在维护线程向量std::vector<ThreadWrapper <threadFuncParam>* > m_vecThreads;

  2. 并将线程推入列表m_vecThreads.push_back(pThreadWrapper);

  3. 当新的请求来了,我采取线程池如下

    if(!m_vecThreads.empty() )
    {
        ThreadWrapper <threadFuncParam>* pWrapper = m_vecThreads.back();
        m_vecThreads.pop_back();
        //... Awake threadd
    }
    
  4. 当线程任务完成时,它被推回线程池。

现在,虽然优雅的关闭,我已经优雅地停止线程现在与上面的设计,我面临的问题,我如何能停止线程,因为在矢量容器我从矢量弹出时请求服务,所以我失去了指针,直到服务完成。是否有更好的我可以做到这一点或处理这种情况像地图或其他容器是由标准c++支持?

另一个问题是

在关机期间,我有一个场景线程正在做进程,在我的情况下,从数据库读取可能需要时间,所以我不能等到它完成我想要回复客户端等待线程正在处理的请求,我要杀死那个值是坏的。

谢谢!

如果仍然需要访问池中分发的内容,则应该将这些项存储在"used"容器中。
然而,此时,您正在共享指针,因此您应该使用shared_ptr并传递weak_ptr,这样线程也可以被删除,并且用户没有悬垂指针

使用过的项的最佳容器是set,这样可以很容易地找到并删除返回的线程。

要解决你的第一个问题,把它推到另一个向量上,比如m_vecBusyThreads,当它完成时,把它从那里拿走(注意,你必须有一些机制来搜索完成的线程)。

对于你的第二个问题,最干净的解决方案是加入每个线程,直到它有"关闭",任何其他方法最终可能会有一些不希望的副作用(特别是,例如,如果它连接到一个数据库等)现在,你有繁忙的容器,迭代通过告诉每个关闭,然后迭代通过你的每个空闲容器,关闭和加入每个线程。然后返回繁忙的容器并尝试连接每个线程。这可以给繁忙的线程一点时间来干净地关闭。

boost::threads支持这种中断点的概念,其想法是您可以在这些点中的任何一个中断线程,然而有些调用是不可中断的(通常是阻塞调用),您需要找到停止每种类型的最佳方法(例如socket读取可能是发送一个虚拟数据包等)

我已经在C中完成了它,因此解决方案不是"c++"式的,但我使用了两个数组:一个包含线程,另一个包含已使用/未使用的表示(~boolean)。

我将是这样的:

pthread_t[INITIAL_SIZE] thread_pool;
boolean[INITIAL_SIZE] threads_availability;
int first_available = 0;
pthread_t * get_thread() {
   int ind = 0;
   if (first_available<=INITIAL_SIZE) {
      ind = first_available;
      // find the next available spot
      for (first_available; first_available < INITIAL_SIZE && threads_availability[first_available]; first_available++);
      threads_availability[ind] = 0;
      return thread_pool[ind];
   }
}
void put_thread(pthread_t* thethread)
{
    int i = 0;
    pthread_t *it = thread_pool;
    while (!pthread_equals(it, thethread)) {
        it++;
        i++;
    }
    thread_availability[i] = 1;
}

请记住,这是伪代码,这不是最佳的。但这是一个想法。

这不是对你问题的直接回答,因为其他人已经回答了你最初的问题。

我只是想说你可以看看boost::asio和/或boost::thread。我可能会选择boost::asio,因为它具有基于计时器和诸如此类的异步操作所需的一切。你可以使用shared_ptr和boost::enable_shared_from_this来让你的"作业"离开,并在它们完成作业时自动销毁。

的例子:

boost::shared_ptr<async_job> aj( new async_job(
   io_, boost::bind(&my_job::handle_completion, shared_from_this(), _1, _2)));

这段代码将在线程池上执行您的自定义async_job (io_是boost::asio::io_service)。当async_job完成并在其上调用handle_completion时,您的'my_job'实例将自动销毁。或者你可以让它存活,如果你在handle_completion中再次执行shared_from_this()。

HTH,亚历克斯