将执行从一个线程转移到另一个线程以实现任务并行性和逐个调用

泡桐

我正在尝试在C ++中实现未来调用机制。尽管这只是一个测试代码(有些急事),但我打算在正在使用的语言的运行时中使用类似的东西来实现透明并行。

我干了我正在处理的代码,以使其变得更小,尽管它仍然很大:

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
#include <future>
#include <thread>
#include <functional>
#include <type_traits>
#include <utility>
using namespace std;
using namespace std::chrono;

//------------------------------------------------------------------------------
// Simple locked printer

static std::recursive_mutex print_lock;

inline void print_() {
  return;
};

template<typename T, typename... Args>
inline void print_(T t, Args... args) {
  print_lock.lock();
  std::cout << t;
  print_(args...);
  print_lock.unlock();
};
//------------------------------------------------------------------------------

template<typename R>
class PooledTask {
  public:
    explicit PooledTask(function<R()>);

    // Possibly execute the task and return the value
    R &operator () () {

      // If we can get the lock, we're not executing
      if(lock.try_lock()) {

        // We may already have executed it
        if(done)
          goto end;

        // Otherwise, execute it now
        try {
          result = move(task());
        } catch(...) {
          // If an exception is thrown, save it for later
          eptr = current_exception();
          failed = true;
        };

        done = true;

        goto end;

      } else {

        // Wait until the task is completed
        lock.lock();

        end: {
          lock.unlock();

          // Maybe we got an exception!
          if(failed)
            rethrow_exception(eptr);

          // Otherwise, just return the result
          return result;
        };
      };
    };

  private:
    exception_ptr eptr;
    function<R()> task;
    bool done;
    bool failed;
    mutex lock;
    R result;
};

extern class TaskPool pool;

class TaskPool {
  public:
    TaskPool() noexcept: TaskPool(thread::hardware_concurrency() - 1) {
      return;
    };

    TaskPool(const TaskPool &) = delete;
    TaskPool(TaskPool &&) = delete;

    template<typename T>
    void push(PooledTask<T> *task) noexcept {

      lock_guard<mutex> guard(lock);

      builders.push([=] {
        try {
          (*task)();
        } catch(...) {
          // Ignore it here! The task will save it. :)
        };
      });

    };

    ~TaskPool() {
      // TODO: wait for all tasks to finish...
    };
  private:
    queue<thread *> threads;
    queue<function<void()>> builders;
    mutex lock;

    TaskPool(signed N) noexcept {
      while(N --> 0)
        threads.push(new thread([this, N] {
          for(;;) {

            pop_task();

          };
        }));
    };

    void pop_task() noexcept {

      lock.lock();

      if(builders.size()) {

        auto task = builders.front();

        builders.pop();

        lock.unlock();

        task();

      } else
        lock.unlock();
    };

} pool;


template<typename R>
PooledTask<R>::PooledTask(function<R()> fun):
  task(fun),
  done(false),
  failed(false)
{
  pool.push(this);
};

// Should probably return a std::shared_ptr here...
template<typename F, typename... Args>
auto byfuture(F fun, Args&&... args) noexcept ->
  PooledTask<decltype(fun(args...))> *
{

  using R = decltype(fun(args...));

  auto pooled = new PooledTask<R> {
    bind(fun, forward<Args>(args)...)
  };

  return pooled;
};


//------------------------------------------------------------------------------
#include <map>

// Get the current thread id as a simple number
static int myid() noexcept {
  static unsigned N = 0;
  static map<thread::id, unsigned> hash;
  static mutex lock;

  lock_guard<mutex> guard(lock);

  auto current = this_thread::get_id();

  if(!hash[current])
    hash[current] = ++N;

  return hash[current];
};
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// The fibonacci test implementation
int future_fib(int x, int parent) {

  if(x < 3)
    return 1;

  print_("future_fib(", x, ")", " on thread ", myid(), \
         ", asked by thread ", parent, "\n");

  auto f1 = byfuture(future_fib, x - 1, myid());
  auto f2 = byfuture(future_fib, x - 2, myid());

  auto res = (*f1)() + (*f2)();

  delete f1;
  delete f2;

  return res;
};
//------------------------------------------------------------------------------

int main() {
  // Force main thread to get id 1
  myid();

  // Get task
  auto f = byfuture(future_fib, 8, myid());

  // Make sure it starts on the task pool
  this_thread::sleep_for(seconds(1));

  // Blocks
  (*f)();

  // Simply wait to be sure all threads are clean
  this_thread::sleep_for(seconds(2));

  //
  return EXIT_SUCCESS;
};

该程序的结果是这样的(我有一个四核,所以池中有3个线程):

future_fib(8) on thread 2, asked by thread 1
future_fib(7) on thread 3, asked by thread 2
future_fib(6) on thread 4, asked by thread 2
future_fib(6) on thread 3, asked by thread 3
future_fib(5) on thread 4, asked by thread 4
future_fib(5) on thread 3, asked by thread 3
future_fib(4) on thread 4, asked by thread 4
future_fib(4) on thread 3, asked by thread 3
future_fib(3) on thread 4, asked by thread 4
future_fib(3) on thread 3, asked by thread 3
future_fib(3) on thread 4, asked by thread 4
future_fib(3) on thread 3, asked by thread 3
future_fib(4) on thread 4, asked by thread 4
future_fib(4) on thread 3, asked by thread 3
future_fib(3) on thread 4, asked by thread 4
future_fib(3) on thread 3, asked by thread 3
future_fib(5) on thread 3, asked by thread 3
future_fib(4) on thread 3, asked by thread 3
future_fib(3) on thread 3, asked by thread 3
future_fib(3) on thread 3, asked by thread 3

与正常的斐波那契函数相比,此实现的速度确实很慢。

所以这里的问题是:当池运行时fib(8),它将创建两个任务,这些任务将在下一个线程上运行,但是当到达auto res = (*f1)() + (*f2)();,两个任务已经在运行,因此它将阻塞f1(在线程3运行)。

我需要做的就是提高线程2的速度,而不是阻塞on f1,以假定线程3正在执行的任务的执行,而准备执行其他任务,因此没有线程会在进行计算。

本文http://bartoszmilewski.com/2011/10/10/async-tasks-in-c11-not-quite-there-yet/中的文章说,有必要做我想做的事,但没有说明如何做。

我的疑问是:我怎么可能那样做?

还有其他选择可以做我想要的吗?

马克斯·加尔金

我认为您可能会遇到目前为C ++标准化提议可恢复功能该建议尚未得到批准,但是Visual Studio 15 CTP实现了该建议,因此您可以尝试制作原型(如果可以使用MSVC编译器)。

Gor Nishanov(最新建议书的作者之一)在CppCon演讲中从23:47开始描述了一个非常相似的示例,该示例使用“父母窃取调度”来计算斐波那契:https : //www.youtube.com/watch? v = KUhSjfSbINE

但是请注意,我找不到实施的任何来源/示例spawnable<T>,因此您可能需要联系提案作者以获取详细信息。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Python将变量从一个线程转移到另一个多线程

来自分类Dev

如何用一些短代码将方法调用转移到另一个线程?

来自分类Dev

将帖子从一个博客转移到另一个博客?

来自分类Dev

将收集对象从一个jsp转移到另一个

来自分类Dev

将数据从一个$ state转移到另一个

来自分类Dev

将变量从一个功能转移到另一个功能

来自分类Dev

使用PHP和MySQL将信息从一个表转移到另一个表

来自分类Dev

如何将数据从一个表转移到另一个2个表

来自分类Dev

将1个随机记录从一个表转移到另一个表

来自分类Dev

Android从一个应用转移到另一个

来自分类Dev

将回购从一个 bitbucket 帐户转移到另一个

来自分类Dev

一次性将所有暂存的文件,文件夹等从一个分支转移到另一个分支

来自分类Dev

一次性将所有暂存的文件,文件夹等从一个分支转移到另一个分支

来自分类Dev

将套接字从一个活动转移到另一个活动

来自分类Dev

将存储库从一个用户帐户转移到另一个用户帐户

来自分类Dev

将项目从一个列表框转移到另一个

来自分类Dev

Selenium Python将Webelement从一个列表转移到另一个列表

来自分类Dev

将钱从一个分行帐户转移到另一个分行帐户

来自分类Dev

将应用程序从一个Admob帐户转移到另一个帐户

来自分类Dev

将构建和发布管道从一个组织转移到另一个组织

来自分类Dev

将变量的值从一个不相关的类转移到另一个

来自分类Dev

将控制权从一个按钮转移到另一个

来自分类Dev

将域从一个办公室门户转移到另一个

来自分类Dev

Selenium Python将Webelement从一个列表转移到另一个列表

来自分类Dev

如何将结构从一个克隆转移到另一个

来自分类Dev

将变量从一个工作簿转移到另一个工作簿vba

来自分类Dev

Angular 2 将变量从一个模板转移到另一个模板

来自分类Dev

如何通过python将皮肤权重从一个骨骼转移到另一个骨骼

来自分类Dev

尝试将数据从异步调用转移到另一个类

Related 相关文章

  1. 1

    Python将变量从一个线程转移到另一个多线程

  2. 2

    如何用一些短代码将方法调用转移到另一个线程?

  3. 3

    将帖子从一个博客转移到另一个博客?

  4. 4

    将收集对象从一个jsp转移到另一个

  5. 5

    将数据从一个$ state转移到另一个

  6. 6

    将变量从一个功能转移到另一个功能

  7. 7

    使用PHP和MySQL将信息从一个表转移到另一个表

  8. 8

    如何将数据从一个表转移到另一个2个表

  9. 9

    将1个随机记录从一个表转移到另一个表

  10. 10

    Android从一个应用转移到另一个

  11. 11

    将回购从一个 bitbucket 帐户转移到另一个

  12. 12

    一次性将所有暂存的文件,文件夹等从一个分支转移到另一个分支

  13. 13

    一次性将所有暂存的文件,文件夹等从一个分支转移到另一个分支

  14. 14

    将套接字从一个活动转移到另一个活动

  15. 15

    将存储库从一个用户帐户转移到另一个用户帐户

  16. 16

    将项目从一个列表框转移到另一个

  17. 17

    Selenium Python将Webelement从一个列表转移到另一个列表

  18. 18

    将钱从一个分行帐户转移到另一个分行帐户

  19. 19

    将应用程序从一个Admob帐户转移到另一个帐户

  20. 20

    将构建和发布管道从一个组织转移到另一个组织

  21. 21

    将变量的值从一个不相关的类转移到另一个

  22. 22

    将控制权从一个按钮转移到另一个

  23. 23

    将域从一个办公室门户转移到另一个

  24. 24

    Selenium Python将Webelement从一个列表转移到另一个列表

  25. 25

    如何将结构从一个克隆转移到另一个

  26. 26

    将变量从一个工作簿转移到另一个工作簿vba

  27. 27

    Angular 2 将变量从一个模板转移到另一个模板

  28. 28

    如何通过python将皮肤权重从一个骨骼转移到另一个骨骼

  29. 29

    尝试将数据从异步调用转移到另一个类

热门标签

归档