【问题标题】:Multithread wrapper多线程包装器
【发布时间】:2017-04-17 14:32:48
【问题描述】:

在我的程序中有很多循环可以很容易地重写为多线程。基本上对于每个应该是多线程的函数,我都在编写以下函数:

void func_to_threaded(int i_from, int i_to, int num_th, ...other_parameters)
{
    int i_min = i_from;
    int i_max = i_to;   
    int i_inc = i_max / num_th;
    i_max = i_max % num_th + i_inc;
    thread* th_dens = new thread[num_th];
    for (int i = 0; i < num_th; i++)
    {
        th_dens[i] = thread(func_one_thread, i_min, i_max, ...other_parameters);
        i_min = i_max;
        i_max += i_inc;
    }
    for (int i = 0; i < num_th; i++) th_dens[i].join();
    delete[] th_dens;
}

有没有办法将它重写为对表单的每个函数都是通用的

void func_one_thread(int i_min, int i_max, ...other_parameters)

【问题讨论】:

  • 只想说,除非i_from 始终为 0,否则该函数看起来并不平均分配工作。尝试使用(3, 8, 2, ...) 在心理上通过它,最终得到thread(func_one_thread, 3, 4, ...)thread(func_one_thread, 4, 8, ...)。所以,除非我错过了什么,否则可能会有点不平衡。
  • 是的,在我的代码中i_from 始终为零,现在我只是尝试更一般地重写它但失败了......
  • 啊。我自己对多线程不太熟悉,但也许i_inc = (i_max - i_min) / num_th; 会起作用。不过,您需要检查 i_max - i_min 是否可以被 num_th 整除,以查看是否有任何线程需要做额外的工作。
  • 是的,我更正了这一点(请参阅下面的答案)。如果 i_max - i_min 不能被 num_thread 整除,那么第一个线程正在做额外的工作 - 由 mod num_thread (%) 实现。
  • 我建议您查看 OpenMP,根据您在运行时拥有的内核数量,它会为您做得很好。

标签: c++ multithreading


【解决方案1】:

我问这个问题已经有一段时间了,我从boost threadpool 回到了更优雅和简单的OpenMP,正如最初建议的Mark Setchell。所以我的代码现在看起来很简单

omp_set_num_threads(num_thread);

#pragma omp parallel for private(private_params)
for(int i = i_min; i < i_max; i++){
    some_func(parameters);
}

【讨论】:

    【解决方案2】:

    根据Piotr Falkowski 的建议,我使用threadpoolboost 库来编写这个类

    // header file
    #include "threadpool.hpp"
    class c_Pool
    {
    public:
        // CONSTRUCTORS
        c_Pool(int num_thread);
    
        // VARIABLES
        int num_thread;
        boost::threadpool::pool th_pool;
    
        // METHODS
        void add_task(int i_from, int i_to, std::function<void(int, int)> func);
    };
    
    // main file
    c_Pool::c_Pool(int num_thread):
        num_thread(num_thread), th_pool(num_thread)
    {}
    
    void c_Pool::add_task(int i_from, int i_to, function<void(int, int)> func)
    {
        int i_min = i_from;
        int i_max = i_to; 
        int i_inc = (i_max - i_min) / num_thread;
        i_max = i_from + i_inc // initial i_max
              + (i_max - i_min) % num_thread; // first thread is doing extra work
    
        for (int i = 0; i < num_thread; i++)
        {
            auto func_one_thread = bind(func, i_min, i_max);        
            th_pool.schedule(func_one_thread);
            i_min = i_max;
            i_max += i_inc;
        }
        th_pool.wait();
    }
    

    每个函数 void some_func(int i_min, int i_max, ...other_parameters) 我都在使用多线程

    auto tmp_func = bind(some_func, placeholders::_1, placeholders::_2, ...other_parameters);
    pool.add_task(i_from, i_to, tmp_func);
    

    EDIT更正了设置初始i_max的行

    【讨论】:

    • 我不确定,但add_task() 的第四行不应该是i_max = i_min + ((i_max - i_min) % num_thread + i_inc); 吗?在该行之后,i_max 目前可能与i_min 相同或小于i_min。 (例如,如果i_from8i_to16,并且num_thread2,那么...i_min 设置为8i_max 设置为16i_inc 设置为 4 ((16 - 8) / 2 -> 8 / 2 -> 4),i_max 设置为 4 ((16 - 8) % 2 + 4 -> @987654350 0 + 4 -> 4)。)除此之外,据我所知,数学看起来不错。
    • 是的,你是对的。在我的程序中,我使用的是i_from = 0,所以我从来没有遇到过这个错误......
    • 如果有些东西看起来有点可疑,尝试用不寻常的输入运行它会很有用,看看它是否正常工作。
    【解决方案3】:

    我不会用模板来回答你的问题,尽管它肯定是一种有效的方法。我将建议您使用线程池,并将您的所有操作包装到一个通用界面中。参见例如:12,带升压:3

    'stay high level'

    【讨论】:

    • 这似乎是一个评论,而不是一个答案,即使我没有从字面上理解“我不会回答你的问题”部分。
    猜你喜欢
    • 2013-05-22
    • 1970-01-01
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多