当前位置: 首页 > 知识库问答 >
问题:

C 11中的线程池

田易安
2023-03-14

有关问题:

关于C 11:

  • C 11: std::线程池?
  • C 11中的异步(启动::a同步)会使线程池过时,以避免昂贵的线程创建吗?

关于升压:

  • C提升线程重用线程
  • 提升::线程并创建一个线程池!

我如何获得发送任务的线程池,而不必一次又一次地创建和删除它们?这意味着持久性线程可以在不加入的情况下重新同步。

我有如下代码:

namespace {
  std::vector<std::thread> workers;

  int total = 4;
  int arr[4] = {0};

  void each_thread_does(int i) {
    arr[i] += 2;
  }
}

int main(int argc, char *argv[]) {
  for (int i = 0; i < 8; ++i) { // for 8 iterations,
    for (int j = 0; j < 4; ++j) {
      workers.push_back(std::thread(each_thread_does, j));
    }
    for (std::thread &t: workers) {
      if (t.joinable()) {
        t.join();
      }
    }
    arr[4] = std::min_element(arr, arr+4);
  }
  return 0;
}

与每次迭代都创建和加入线程不同,我更愿意在每次迭代中将任务发送给我的工作线程,并且只创建一次。

共有3个答案

谷梁承宣
2023-03-14

线程池意味着所有线程都在运行,也就是说,线程函数永远不会返回。为了给线程一些有意义的事情去做,您必须设计一个线程间通信系统,既可以告诉线程有事情要做,也可以通信实际的工作数据。

通常,这将涉及某种并发数据结构,每个线程可能会在某种条件变量上Hibernate,当有工作要做时,会通知这些条件变量。收到通知后,一个或多个线程将唤醒,从并发数据结构中恢复任务,对其进行处理,并以类似的方式存储结果。

然后,线程会继续检查是否有更多的工作要做,如果没有,就继续睡觉。

结果是你必须自己设计所有这些,因为没有一个普遍适用的“工作”的自然概念。这是相当多的工作,有些微妙的问题你必须解决。(如果你喜欢一个在幕后为你处理线程管理的系统,你可以在Go中编程。)

曹疏珂
2023-03-14

您可以使用C线程池库,https://github.com/vit-vit/ctpl.

然后您编写的代码可以替换为以下代码

#include <ctpl.h>  // or <ctpl_stl.h> if ou do not have Boost library

int main (int argc, char *argv[]) {
    ctpl::thread_pool p(2 /* two threads in the pool */);
    int arr[4] = {0};
    std::vector<std::future<void>> results(4);
    for (int i = 0; i < 8; ++i) { // for 8 iterations,
        for (int j = 0; j < 4; ++j) {
            results[j] = p.push([&arr, j](int){ arr[j] +=2; });
        }
        for (int j = 0; j < 4; ++j) {
            results[j].get();
        }
        arr[4] = std::min_element(arr, arr + 4);
    }
}

您将获得所需的线程数,并且不会在迭代中一遍又一遍地创建和删除它们。

公冶泰
2023-03-14

这是从我的回答复制到另一个非常类似的帖子:

>

  • 系统可以支持的最大线程数开始:

    int num_threads = std::thread::hardware_concurrency();
    

    为了实现高效的线程池,一旦根据num_threads创建了线程,最好不要创建新线程,也不要破坏旧线程(通过加入)。这将导致性能下降,甚至可能使应用程序运行速度比串行版本慢。

    每个C11线程应该以无限循环的方式在其函数中运行,不断等待新任务的抓取和运行。

    下面是如何将这样一个函数附加到线程池:

    int num_threads = std::thread::hardware_concurrency();
    std::vector<std::thread> threads;
    for (int i = 0; i < num_threads; i++)
    {
        pool.push_back(std::thread(Infinite_loop_function));
    }
    
    void Pool::Infinite_loop_function()
    {
        while (true)
        {
            {
                std::unique_lock<std::mutex> lock(queue_mutex);
    
                condition.wait(lock, [this](){
                    return !queue.empty() || terminate_pool;
                });
                Job = queue.front();
                queue.pop();
            }
    
            Job(); // function<void()> type
        }
    };
    
    void Pool::Add_Job(function<void()> New_Job)
    {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            queue.push(New_Job);
        }
    
        condition.notify_one();
    }
    
    Pool_Obj.Add_Job(std::bind(&Some_Class::Some_Method, &Some_object));
    

    一旦您集成了这些成分,您就拥有了自己的动态线程池。这些线程总是运行,等待作业完成。

    如果有一些语法错误,我道歉,我打了这个代码,我有一个坏的记忆。很抱歉,我不能提供完整的线程池代码;这将违反我的工作完整性。

    编辑:要终止池,请调用Shutdown()方法:

    Pool::shutdown()
    {
        {
            std::unique_lock<std::mutex> lock(threadpool_mutex);
            terminate_pool = true; // use this flag in condition.wait
        }
    
        condition.notify_all(); // wake up all threads.
    
        // Join all threads.
        for (std::thread &th : threads)
        {
            th.join();
        }
    
        pool.clear();  
        stopped = true; // use this flag in destructor, if not set, call shutdown() 
    }
    

  •  类似资料:
    • 我对最新gcc中基于pthread和Ubuntu开发环境的线程的互斥锁和消息传递的性能感兴趣。一个很好的通用问题是用餐哲学家,每个哲学家使用lh和rh叉子与左右手邻居共享。我把哲学家的数量增加到99个,让我的四核处理器保持忙碌。 上面的代码允许我的哲学家尝试抓住他们需要的两个叉子。 上面的代码监控我的哲学家的进食或思考进度,这取决于他们是否能够保留这两个叉子。 在所有哲学家尝试自由选择后,等待所有

    • 我在Ubuntu13.04桌面上运行这个非常简单的程序,但是如果我注释掉sleep_for一行,它会在从main打印cout后挂起。有人能解释为什么吗?据我所知,main是一个线程,t是另一个线程,在本例中,互斥体管理共享cout对象的同步。

    • 如何从线程池中找到60%(或N%)的线程可用性?这背后的逻辑是什么? 父线程使用线程池线程生成多个网址,并等待所有子线程完成。 代码如下所示 父线程 子线程 用于跨线程通信的对象数据 在上述代码中,所需的线程硬编码为: 这种硬编码会导致线程池不足吗?如果线程池中没有可用的线程,会发生什么?如何在托管服务器的线程池中查找可用线程的总数? 谢谢。

    • 本文向大家介绍详解python中的线程与线程池,包括了详解python中的线程与线程池的使用技巧和注意事项,需要的朋友参考一下 线程 进程和线程 什么是进程? 进程就是正在运行的程序, 一个任务就是一个进程, 进程的主要工作是管理资源, 而不是实现功能 什么是线程? 线程的主要工作是去实现功能, 比如执行计算. 线程和进程的关系就像员工与老板的关系, 老板(进程) 提供资源 和 工作空间, 员工(

    • 如果我有一个固定大小的线程池,它什么时候真正调用启动线程?(它会在创建时启动它们吗?还是等到我开始提交任务时再启动?)

    • 本文向大家介绍C#线程处理系列之线程池中的I/O线程,包括了C#线程处理系列之线程池中的I/O线程的使用技巧和注意事项,需要的朋友参考一下 一、I/O线程实现对文件的异步  1.1  I/O线程介绍: 对于线程所执行的任务来说,可以把线程分为两种类型:工作者线程和I/O线程。 工作者线程用来完成一些计算的任务,在任务执行的过程中,需要CPU不间断地处理,所以,在工作者线程的执行过程中,CPU和线程

    • 我找到了关于线程安全的代码,但它没有来自给出示例的人的任何解释。我想知道为什么如果我不在“count”之前设置“synchronized”变量,那么count值将是非原子的(总是=200是期望的结果)。谢谢