github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/3rd_party/fflib/src/functionflow/runtime.cpp (about)

     1  /***********************************************
     2    The MIT License (MIT)
     3  
     4    Copyright (c) 2012 Athrun Arthur <athrunarthur@gmail.com>
     5  
     6    Permission is hereby granted, free of charge, to any person obtaining a copy
     7    of this software and associated documentation files (the "Software"), to deal
     8    in the Software without restriction, including without limitation the rights
     9    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    10    copies of the Software, and to permit persons to whom the Software is
    11    furnished to do so, subject to the following conditions:
    12  
    13    The above copyright notice and this permission notice shall be included in
    14    all copies or substantial portions of the Software.
    15  
    16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    21    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    22    THE SOFTWARE.
    23   *************************************************/
    24  #include "ff/functionflow/runtime/runtime.h"
    25  #include "ff/functionflow/runtime/rtcmn.h"
    26  
    27  namespace ff {
    28  extern bool g_initialized_flag;
    29  void initialize(size_t concurrency) {
    30    rt::set_concurrency(concurrency);
    31    rt::runtime::instance();
    32  }
    33  
    34  namespace rt {
    35  std::shared_ptr<runtime_deletor> runtime_deletor::s_pInstance(nullptr);
    36  runtime_ptr runtime::s_pInstance(nullptr);
    37  std::once_flag runtime::s_oOnce;
    38  
    39  void schedule(task_base_ptr p) {
    40    static runtime_ptr r = runtime::instance();
    41    r->schedule(p);
    42  }
    43  void yield() { std::this_thread::yield(); }
    44  
    45  runtime::runtime()
    46      : m_pTP(new threadpool()), m_oQueues(), m_bAllThreadsQuit(false),
    47        m_scheduler_thread_running_count(0){};
    48  
    49  runtime::~runtime() {
    50    abort_all_tasks_and_quit();
    51    // std::unique_lock<std::mutex> _k(m_join_mutex);
    52    // m_bAllThreadsQuit = true;
    53    //{
    54    // std::unique_lock<std::mutex> _l(m_wakeup_mutex);
    55    // m_wakeup.notify_all();
    56    //}
    57    // m_pTP->join();
    58  }
    59  
    60  runtime_ptr runtime::instance() {
    61    if (!s_pInstance) std::call_once(s_oOnce, runtime::init);
    62    return s_pInstance;
    63  }
    64  
    65  
    66  void runtime::init() {
    67    s_pInstance = new runtime();
    68    runtime_deletor::s_pInstance = std::make_shared<runtime_deletor>(s_pInstance);
    69    auto thrd_num = concurrency();
    70    for (int i = 0; i < thrd_num; ++i) {
    71      s_pInstance->m_oQueues.push_back(
    72          std::unique_ptr<work_stealing_queue>(new work_stealing_queue()));
    73      s_pInstance->m_oWQueues.push_back(
    74          std::unique_ptr<simo_queue_t>(new simo_queue_t()));
    75    }
    76    s_pInstance->m_sleep_counter = 0;
    77  
    78    set_local_thrd_id(0);
    79  
    80    for (int i = 1; i < thrd_num; ++i) {
    81      s_pInstance->m_pTP->run([i]() {
    82        auto r = runtime::instance();
    83        set_local_thrd_id(i);
    84        r->thread_run();
    85      });
    86    }
    87    g_initialized_flag = true;
    88  }
    89  
    90  void runtime::init_for_no_ff_thread() {
    91    m_queue_mutex.lock();
    92    m_oWQueues.push_back(std::unique_ptr<simo_queue_t>(new simo_queue_t()));
    93    m_oQueues.push_back(
    94        std::unique_ptr<work_stealing_queue>(new work_stealing_queue()));
    95    m_queue_mutex.unlock();
    96    size_t t = std::atomic_fetch_add(&s_current_concurrency, (size_t)1);
    97    set_local_thrd_id(t);
    98  }
    99  void runtime::schedule(task_base_ptr p) {
   100    thread_local static int i = get_thrd_id();
   101    if (i == invalid_thrd_id) {
   102      init_for_no_ff_thread();
   103      i = get_thrd_id();
   104    }
   105    if (!m_oQueues[i]->push_back(p)) {
   106      m_scheduler_thread_running_count++;
   107      if (!m_bAllThreadsQuit) {
   108        run_task(p);
   109      }
   110      m_scheduler_thread_running_count--;
   111    } else if (m_sleep_counter > 1) {
   112      m_wakeup.notify_one();
   113    }
   114  }
   115  
   116  bool runtime::take_one_task(task_base_ptr &pTask) {
   117    bool b = false;
   118    thread_local static int i = get_thrd_id();
   119    thread_local static uint64_t ct = 0;
   120    b = m_oQueues[i]->pop(pTask);
   121    if (!b) {
   122      ct++;
   123      if ((ct & 0x1) == 0) {
   124        b = m_oWQueues[i]->pop(pTask);
   125        if (!b) {
   126          b = steal_one_task(pTask);
   127        }
   128      } else {
   129        b = steal_one_task(pTask);
   130        if (!b) {
   131          b = m_oWQueues[i]->pop(pTask);
   132        }
   133      }
   134    }
   135    return b;
   136  }
   137  
   138  void runtime::run_task(task_base_ptr &pTask) {
   139    thread_local static int cur_id = get_thrd_id();
   140    pTask->run();
   141    while (pTask->need_to_reschedule() && !m_oWQueues[cur_id]->push(pTask))
   142      pTask->run();
   143  }
   144  
   145  void runtime::abort_all_tasks_and_quit() {
   146    std::unique_lock<std::mutex> _k(m_join_mutex);
   147    if (m_bAllThreadsQuit)
   148      return;
   149  
   150    m_bAllThreadsQuit = true;
   151    while (m_scheduler_thread_running_count > 0) {
   152      std::this_thread::yield();
   153    }
   154  
   155    {
   156      std::unique_lock<std::mutex> _l(m_wakeup_mutex);
   157      m_wakeup.notify_all();
   158    }
   159    m_pTP->join();
   160  }
   161  void runtime::thread_run() {
   162    bool flag = false;
   163    thread_local static int cur_id = get_thrd_id();
   164    task_base_ptr pTask;
   165    size_t dis = 1;
   166    while (!m_bAllThreadsQuit) {
   167      size_t ts = m_oQueues.size();
   168      int8_t retry_counter = 3;
   169      while (retry_counter > 0) {
   170        flag = take_one_task(pTask);
   171        if (flag) {
   172          run_task(pTask);
   173          retry_counter = 3;
   174        }
   175        if (!flag) {
   176          yield();
   177          retry_counter--;
   178        }
   179      }
   180      std::unique_lock<std::mutex> _l(m_wakeup_mutex);
   181      if (!m_bAllThreadsQuit) {
   182        m_sleep_counter++;
   183        m_wakeup.wait(_l);
   184        m_sleep_counter--;
   185      }
   186    }
   187  }
   188  
   189  bool runtime::steal_one_task(task_base_ptr &pTask) {
   190    thread_local static int cur_id = get_thrd_id();
   191    size_t dis = 1;
   192    size_t ts = m_oQueues.size();
   193    while ((cur_id + dis) % ts != cur_id) {
   194      if (m_oQueues[(cur_id + dis) % ts]->steal(pTask)) {
   195        return true;
   196      } else if (m_oWQueues[(cur_id + dis) % ts]->pop(pTask)) {
   197        return true;
   198      }
   199      dis++;
   200    }
   201    return false;
   202  }
   203  }  // end namespace rt
   204  void abort_all_tasks_and_quit() {
   205    static rt::runtime_ptr r = rt::runtime::instance();
   206    r->abort_all_tasks_and_quit();
   207  }
   208  }  // end namespace ff