【问题标题】:Boost::thread thread() not accepting argumentsBoost::thread thread() 不接受参数
【发布时间】:2015-02-07 21:12:35
【问题描述】:

IDE 向我抱怨线程不包含我传递给它的参数数量。这是因为他们太多了,我相信......

我在使用线程标准库时遇到了同样的问题,但是对于兼容性问题,我需要使用 Boost::threads。 HERE 是我之前的问题的链接,有人解释说问题是由 veriadic 模板引起的。

这确实是问题所在,但是,在切换到 boost 线程后,该错误又回来了,更改 veriadic max 并不能解决它。

这是我的线程声明

boost::thread db(writeToDB, coordString, time, std::to_string(id), imageName, azimuth, att_pitch, att_roll, yaw, cam_pitch, cam_roll);

编辑:

这是我尝试绑定功能的方法:

boost::thread db(boost::bind(::writeToDB, coordString, time, std::to_string(id), imageName, azimuth, att_pitch, att_roll, yaw, cam_pitch, cam_roll));

目前的IDE是Visual Studio 2013,不过需要兼容Visual Studio 2008

这也是我收到的实际错误:

错误:

Error 6 error C2661: 'boost::thread::thread' : no overloaded function takes 11 arguments c:\users\hewittjc\desktop\final project\project1\clientexample.cpp 174 1 Project1

【问题讨论】:

  • 一个简单的谷歌搜索给出了答案 - 重复 stackoverflow.com/questions/5730747/…
  • 我试过bind函数,和thread一样报错
  • 请告诉我们你是如何在线程构造函数中使用bind方法的?
  • 什么是The IDE?实际错误是什么?
  • 我已经在编辑中回答了上述问题。感谢您的关注!

标签: c++ multithreading boost


【解决方案1】:

Boost.Thread(内部利用 Boost.Bind 绑定参数)仅支持 一些 固定数量的参数 (doc):

带参数的线程构造函数

template <class F,class A1,class A2,...>
thread(F f,A1 a1,A2 a2,...);

前提条件:

F 和每个An 必须是可复制或可移动的。

效果:

好像thread(boost::bind(f,a1,a2,...))。因此,f 和每个an 都被复制到内部存储中以供新线程访问。

后置条件:

*this 指的是新创建的执行线程。

抛出:

boost::thread_resource_error 如果发生错误。

错误情况:

resource_unavailable_try_again : 系统缺乏必要的资源来创建另一个线程,或者系统对进程中的线程数施加的限制将被超过。

注意:

目前除了函数 f 之外,还可以指定多达 9 个附加参数 a1a9

显然,这意味着传递 11 个参数(如您所做的那样)必然会导致您看到的错误:“没有重载的函数需要 11 个参数”

不幸的是,没有简单的方法来扩展限制。可能的解决方案是:

  • 减少参数的总数(你只比限制多一个)

  • 使用其他库来绑定参数,例如 Boost.Phoenix

  • 在类类型变量中包装参数(或至少其中一些)

  • 在完全支持可变参数模板的 C++11 编译器上切换到 std::thread

【讨论】:

  • 最终传递了一个结构,但我想我应该已经看到了注意:那里是吧?哈。谢谢!
【解决方案2】:

来自Boost.Thread documentation

注意:

目前除了函数 f 之外,最多可以指定九个附加参数 a1 到 a9。

Boost.Bind 有同样的限制。你可以试试std::tr1::bind,MSVC 2008 有它,但我怀疑它在那里会很相似——你真的需要可变参数模板来正确地制作bind,而 MSVC 2008 没有它们。我认为唯一真正疯狂到能够通过预处理器元编程实现这一点的人是 Boost.Spirit 人,他们将其变成了 Boost.Phoenix。在那里你可以通过预处理器指定一个上限,如下所示:

// Set this before headers are included.
// ...best set it projectwide. I don't know if funny stuff happens if Phoenix is
// used with different limits in different translation units.
//
// Also, please read the stuff below.
//
#define BOOST_PROTO_MAX_ARITY 20
#define BOOST_PROTO_MAX_LOGICAL_ARITY 20

#include <boost/phoenix/bind.hpp>
#include <boost/thread.hpp>

#include <iostream>

void foo(int x0, int x1, int x2, int x3, int x4,
         int x5, int x6, int x7, int x8, int x9,
         int x10)
{
  std::cout << x0 << x1 << x2 << x3 << x4
            << x5 << x6 << x7 << x8 << x9
            << x10 << "\n";
}

int main() {
  boost::thread th(boost::phoenix::bind(&foo, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
  th.join();
}

现在,这个功能相当粗糙。我觉得控制这个的预处理器宏被视为事后的想法。在 Boost.Phoenix 文档中,它说您应该能够通过 BOOST_PHOENIX_LIMIT 来控制它,这曾经是真的,但是在创建 Boost.Proto 主干的过程中,它似乎已经发生了变化,并且文档没有更新。在其他方面,它的边缘也很粗糙。例如,它只适用于我的值为 20(如果你真的有耐心的话,我怀疑是 30、40 等)——从 11 到 19 的任何值都会产生巨大的编译器错误——而且需要很长时间才能编译,因为它突然有 1048576 个函数模板重载需要处理。

所以这行得通(对我来说,使用 Boost 1.55.0),但它并不是真正可以依赖的东西。相反,我建议你要么将你的参数组合在结构中,这样你就可以将少于 10 个参数传递给writeDB,或者你编写自己的仿函数(使用二十一点和......没关系),比如

// "..." to mean the rest of the arguments
class writeDBFunctor {
public:
  writeDBFunctor(std::string coordString, ...) : coordString(cordString), ... { }

  void operator()() {
    writeDB(coordString, ...);
  }

private:
  std::string coordString;
  // ...and the other arguments saved here
}

并将其交给boost::thread

【讨论】:

    【解决方案3】:

    如果你想使用 boost 线程,你只需要创建一个临时的“东西盒”。简单的例子: 我想提升::线程关注...

    /// d2dclass
    static void draw_tree(ID2D1RenderTarget* d2rt,
                          ID2D1Brush*        brush,
                          float X, float Y, float len,
                          int level,
                          float angle = -DirectX::XM_PIDIV2,
                          float dispersion = DirectX::XM_PIDIV2,
                          int split = 2, float shrink = 0.5f,
                          float sw = 1.0f,
                          ID2D1StrokeStyle* ss = NULL,
                          HANDLE interrupt = NULL);
    

    它是一个简单的递归 D2D1 树绘制函数。

    定义一个参数数据持有者。

    struct dth_para {
        ID2D1RenderTarget* _d2rt;
        ID2D1Brush*      _brush;
        float _X;
        float _Y;
        float _len;
        int _level;
        float _angle;
        float _dispersion;
        int _split;
        float _shrink;
        float _sw;
        ID2D1StrokeStyle* _ss;
        HANDLE _interrupt;
    };
    

    使用 boost::thread& 定义一个简单的线程调用版本(参考)使用模板。 (你可能想同时做几个)和一个 impl 版本。 实际上这部分我不确定它是否需要。每个线程都会创建单独的工作区,但不会受到伤害。 在第一个函数中声明一个静态变量,这样它就不会从堆栈中消失。

    /// class d2dclass
    
    template<size_t num_tree>
    static void draw_tree_thread(boost::thread& tth,
                                 ID2D1RenderTarget* d2rt,
                                 ID2D1Brush*         brush,
                                 float X, float Y, float len,
                                 int level,
                                 float angle = -DirectX::XM_PIDIV2,
                                 float dispersion = DirectX::XM_PIDIV2,
                                 int split = 2, float shrink = 0.5f,
                                 float sw = 1.0f,
                                 ID2D1StrokeStyle* ss = NULL,
                                 HANDLE interrupt = NULL) {
        static dth_para tree_para;
        tree_para._d2rt = d2rt;
        tree_para._brush = brush;
        tree_para._X = X;
        tree_para._Y = Y;
        tree_para._len = len;
        tree_para._level = level;
        tree_para._angle = angle;
        tree_para._dispersion = dispersion;
        tree_para._split = split;
        tree_para._shrink = shrink;
        tree_para._sw = sw;
        tree_para._ss = ss;
        tree_para._interrupt = interrupt;
        tth = boost::thread(boost::bind(&draw_tree_thread_mpl, boost::ref(tree_para)));
    }
    
    static void draw_tree_thread_mpl(dth_para& params) {
        draw_tree(params._d2rt,
                  params._brush,
                  params._X,
                  params._Y,
                  params._len,
                  params._level,
                  params._angle,
                  params._dispersion,
                  params._split,
                  params._shrink,
                  params._sw,
                  params._ss,
                  params._interrupt);
    }
    

    并且只需调用适当的函数。

    boost::thread sth;
    d2dclass::draw_tree_thread<0>(sth,
                                  d3d->getd2rendertarget(),
                                  pRadialGradientBrush0,
                                  d3d->get_ww() / 2,
                                  d3d->get_wh() - TREE_LEN,
                                  TREE_LEN,
                                  LEVELS,
                                  -DirectX::XM_PIDIV2,
                                  DISPERSION,
                                  2,
                                  OPA_SHRINK,
                                  -6.0f,
                                  NULL,
                                  interrupt);
    

    【讨论】:

      猜你喜欢
      • 2017-02-20
      • 2012-03-23
      • 2020-12-21
      • 1970-01-01
      • 2011-01-11
      • 2010-11-06
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      相关资源
      最近更新 更多