c++ - 线程可以被重用来运行可变参数函数吗?

标签 c++ multithreading boost-thread variadic-templates

我正在尝试在 C++ 中创建一个 boost 线程,它可以重复用于运行可以具有不同数量和类型的 args 的各种函数。

这可以用 C++11x 可变参数来完成吗?

在我的用例中,我不需要队列(如果线程繁忙,那么该方法就会失败),但如果需要实现此“统一”功能,我会不情愿地这样做。

我不明白如何使用 bind 或 lambda 处理统一,以便一个线程可以调用不同的函数,每个函数都有自己的不同数量和类型的参数。

我大概想到了以下几点:

class WorkThread
{
public:
   WorkThread()
       {
       // create thread and bind runner to thread
       }

   ~WorkThread()
       {
       // tell runner to exit and wait and reap the thread
       }

   template<typename F,typename ... Arguments>
   void doWork(F func, Arguments... args)
       {
       if already busy
           return false;
       // set indication to runner that there is new work
       // here: how to pass f and args to runner?
       }

private:
   void runner()
        {
        while ( ! time to quit )
            {
            wait for work
            // here: how to get f and args from doWork? do I really need a queue? could wait on a variadic signal maybe?
            f(args);
            }
        }

   boost::thread* m_thread;
};

class ThreadPool
{
public:
    template<typename F, typename ... Arguments>
    bool   doWork(F func,Arguments... args)
          {
          const int i = findAvailableWorkThread();
          m_thread[i].doWork(f,args);
          }
private:
   // a pool of work threads m_thread;
};

最佳答案

应该有很多现有的问题来说明如何做到这一点。

表示任意函数对象的规范 C++11 方法是 std::function<void()> ,因此您需要一个名为 m_job 的该类型的共享对象在下面的代码中,它应该受到互斥锁的保护,并且在尚未设置时为其分配新作业:

template<typename F,typename ... Arguments>
bool doWork(F func, Arguments&&... args)
{
    std::lock_guard<std::mutex> l(m_job_mutex);
    if (m_job)
        return false;
    m_job = std::bind(func, std::forward<Arguments>(args)...);
    m_job_cond.notify_one();  
    return true;   
}

这使用 std::bind将函数对象及其参数转换为不带参数的函数对象。 std::bind 返回的可调用对象存储 func 的拷贝和每个参数,并在调用时调用 func(args...)

然后 worker 就做:

void runner()
{
    while ( ! time to quit )
    {
        std::function<void()> job;
        {
            std::unique_lock<std::mutex> l(m_job_mutex);
            while (!m_job)
                m_job_cond.wait(l);
            swap(job, m_job);
        }
        job();
    }
}

这段代码不是线程安全的:

template<typename F, typename ... Arguments>
    bool   doWork(F func,Arguments... args)
    {
        const int i = findAvailableWorkThread();
        m_thread[i].doWork(f,args);
    }

findAvailableWorkThread 之后返回,该线程可能会变得繁忙,因此下一行将失败。您应该检查可用性并在单个操作中通过新作业,例如

template<typename F, typename ... Arguments>
    bool   doWork(F func,Arguments... args)
    {
        for (auto& t : m_thread)
            if (t.doWork(f,args))
                return true;
        return false;
    }

关于c++ - 线程可以被重用来运行可变参数函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15237426/

相关文章:

c++ - 如何模拟 alignas(T)?

c++ - 从文件中连续读取管道字节

C++ 观察者模式监听器事件方法/类或信号和槽

c++ - 交叉编译找不到引用

c++ - 为什么所有内核上的 sin(Vector) 可以和一个内核上的 sin(V) 一样快?

c# - 停止线程的最佳方法

c++ - poco ping 线程安全吗

c++ - 提升线程取消

c++ - 用 Metrowerks 编译器解决 boost.thread 编译错误

c++ - 我如何将 boost::this_thread::get_id() 转换为 int?