【问题标题】:Creating threads that copy the arguments passed to them创建复制传递给它们的参数的线程
【发布时间】:2010-08-16 22:17:02
【问题描述】:

我目前正在使用 boost::thread,因为它非常方便地允许我将任意数量的参数传递给线程并沿途复制它们,所以我不必担心它们在线程启动。是否有任何其他库允许这样做,或者使用 pthreads 模拟它的方法?我想摆脱 boost,但我从未见过任何其他图书馆这样做。

【问题讨论】:

  • 看看boost是怎么做到的,他们的大部分代码都在头文件中。
  • Boost 线程不是他们的头文件库之一。不过,如果没有其他可用的库,我可能会查看他们的代码。
  • 拥有一个函数(实际上是一个或多个模板中的许多函数)需要一些模板工作,该函数接受可变数量的参数并“知道”它们的类型以便能够复制他们。这是提升,它可能是相当繁重的模板工作。当其他库不这样做时,这是因为他们不同意 boost 的观点,如果它没有按照您想要的方式工作,请继续向它扔模板,直到它完成为止。或者提升贡献者使其发挥作用的能力......
  • C++0x 将包含线程,而且很快就会推出,我想我现在只能坚持使用 Boost 线程,并在原生线程支持可用时切换。

标签: c++ c pthreads


【解决方案1】:

我不记得 Boost.Thread 的细节,但大致的想法是这样的:

class thread_function_base
{
public:
    virtual ~thread_function_base(void) {}
    virtual void run(void) = 0;
};

template <typename Func>
class thread_function_0 : public thread_function_base
{
public:
    thread_function_0(const Func& pFunc) :
    mFunc(pFunc)
    {}

    void run(void)
    {
        mFunc();
    }

private:
    Func mFunc;
};

template <typename Func, typename A0>
class thread_function_1 : public thread_function_base
{
public:
    thread_function_1(const Func& pFunc, const A0& pA0) :
    mFunc(pFunc),
    mA0(pA0)
    {}

    void run(void)
    {
        mFunc(mA0);
    }

private:
    Func mFunc;
    A0 mA0;
};

// and so on to some limit, either
// generated either by hand (yuck), by
// Boost.PP (phew), or by C++0x's
// variadic templates (yay, no limit either)

class thread
{
public:
    template <typename Func>
    thread(const Func& pFunc)
    {
        std::auto_ptr<thread_function_base>
            threadFunc(new thread_function_0<Func>(pFunc));

        create_thread(threadFunc);
    }

    template <typename Func, typename A0>
    thread(const Func& pFunc, const A0& pA0)
    {
        std::auto_ptr<thread_function_base>
            threadFunc(new thread_function_1<Func, A0>(pFunc, pA0));

        create_thread(threadFunc);
    }

    // again, needs to be generated somehow

private:
    // noncopyable
    thread(const thread&);
    thread& operator=(const thread&);

    // signature needs to match implementations expectations:
    static void thread_function(void* pUserData)
    {
        std::auto_ptr<thread_function_base>
            pFunc(static_cast<thread_function_base*>(pUserData));

        // (A)

        pFunc->run();
    }

    void create_thread(std::auto_ptr<thread_function_base>& pThreadFunc)
    {
        // again, implementation specific function:
        if (create_thread(&thread_function, pThreadFunc.get(), ...))
        {
            // failed, do something (and return), 
            // auto_ptr in constructor will free resources
            return;
        }    

        // thread was created, so it now owns that resource
        pThreadFunc.release();

        // (B)
    }
};

基本上,调用线程所需的一切都被复制到某个动态分配的容器中,指向该动态容器的指针被传递给线程函数(微不足道),然后所有权从线程外部转移到内部。

您不仅可以将thread_function_base 打包到用户数据中,还可以将(特定于实现的)信号句柄打包,从而使事情变得更安全。线程函数将在(A) 处阻塞,直到在(B) 处发出信号,这表明主线程已将资源的完全所有权授予工作线程。 (从那里auto_ptr 最终会删除它。)

等等,让它变得更加复杂。

【讨论】:

    【解决方案2】:

    例如,您必须围绕 pthread_create 创建一个包装器,并将线程特定的存储传递给 pthread_create,其中包含一个参数数组。包装器将使用如下形式:

    void *mythreadfunction(void *arg) {...}
    
    pthread_create_wrapper(context ctx, ...) {
       Array *arr;
       pthread_t mythread;
    
       arr = new Array();
    
       // push arguments to array here
       blah blah ...
       // create thread and pass in argument list as thread data pointer.
       pthread_create(&mythread, NULL, mythreadfunction, (void *)arr);
    } 
    

    【讨论】:

      猜你喜欢
      • 2012-10-19
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-08
      • 2014-01-05
      相关资源
      最近更新 更多